0%

SpringBoot-整合Shiro

前言

  • Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro 要简单的多。
  • 三个核心组件:Subject,SecurityManager 和 Realms.
    Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
    Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
    SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
    Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。Shiro可参考跟我学Shiro

pom.xml文件

这里添加了web、jpa、mysql、shiro和thymeleaf依赖。jpa可参考 SpringBoot 整合JPA ,thymeleaf可参考SpringBoot 整合Thymeleaf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<nekohtml.version>1.9.22</nekohtml.version>
<shiro.version>1.4.0</shiro.version>
</properties>

<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>

<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!--HTML解析器和标记平衡器。-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>${nekohtml.version}</version>
</dependency>

<!-- 调试热启动 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

配置文件

采用jpa作为数据库持久层框架,建表的任务交给框架自动完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
spring:
#数据库配置
datasource:
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver

#jpa配置
jpa:
hibernate:
ddl-auto: update
show-sql: true

thymeleaf:
# 是否开启模板缓存,默认true
# 建议在开发时关闭缓存,不然没法看到实时页面
cache: false
##去除thymeleaf的html严格校验
mode: LEGACYHTML5
# 模板编码
encoding: utf-8

#端口号
server:
port: 8080

实体类

这里主键采用uuid方式,ManyToMany做对应关系。

  • SysUser.java: 用户实体类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    @Entity
    @Table(name = "sys_user")
    public class SysUser implements Serializable {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id;
    @Column(unique = true)
    private String userName; //帐号
    private String name; //名称(昵称或者真实姓名,不同系统不同定义)
    private String passWord; //密码;
    private String salt; //加密密码的盐
    private byte state; //用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.

    //多对多关系
    //急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载
    //FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "userId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
    private List<SysRole> roles; // 一个用户具有多个角色

    public String getId() {
    return id;
    }

    public void setId(String id) {
    this.id = id;
    }

    public String getUserName() {
    return userName;
    }

    public void setUserName(String userName) {
    this.userName = userName;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getPassWord() {
    return passWord;
    }

    public void setPassWord(String passWord) {
    this.passWord = passWord;
    }

    public String getSalt() {
    return salt;
    }

    public void setSalt(String salt) {
    this.salt = salt;
    }

    public byte getState() {
    return state;
    }

    public void setState(byte state) {
    this.state = state;
    }

    public List<SysRole> getRoles() {
    return roles;
    }

    public void setRoles(List<SysRole> roles) {
    this.roles = roles;
    }

    //重新对盐重新进行了定义,用户名+salt,这样就更加不容易被破解
    public String getCredentialsSalt() {
    return this.userName + this.salt;
    }
    }
  • SysRole.java:角色实体类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    @Entity
    @Table(name = "sys_role")
    public class SysRole implements Serializable {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id; // 编号
    private String role; // 角色标识程序中判断使用,如"admin",这个是唯一的:
    private String description; // 角色描述,UI界面显示使用
    private Boolean available = Boolean.FALSE; // 是否可用,如果不可用将不会添加给用户

    //角色 -- 权限关系:多对多关系;
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "SysRolePermission", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "permissionId")})
    private List<SysPermission> permissions;

    // 用户 - 角色关系定义;
    @ManyToMany
    @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "userId")})
    private List<SysUser> users;// 一个角色对应多个用户

    public String getId() {
    return id;
    }

    public void setId(String id) {
    this.id = id;
    }

    public String getRole() {
    return role;
    }

    public void setRole(String role) {
    this.role = role;
    }

    public String getDescription() {
    return description;
    }

    public void setDescription(String description) {
    this.description = description;
    }

    public Boolean getAvailable() {
    return available;
    }

    public void setAvailable(Boolean available) {
    this.available = available;
    }

    public List<SysPermission> getPermissions() {
    return permissions;
    }

    public void setPermissions(List<SysPermission> permissions) {
    this.permissions = permissions;
    }

    public List<SysUser> getUsers() {
    return users;
    }

    public void setUsers(List<SysUser> users) {
    this.users = users;
    }
    }
  • SysPermission:权限实体类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    @Entity
    @Table(name = "sys_permission")
    public class SysPermission implements Serializable {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id; //主键.
    private String name; //名称.
    @Column(columnDefinition = "enum('menu','button')")
    private String resourceType; //资源类型,[menu|button]
    private String url; //资源路径.
    private String permission; //权限字符串,menu例子:role:*,button例子:role:create,role:update,role:delete,role:view
    private Long parentId; //父编号
    private String parentIds; //父编号列表
    private Boolean available = Boolean.FALSE;
    @ManyToMany
    @JoinTable(name = "SysRolePermission", joinColumns = {@JoinColumn(name = "permissionId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
    private List<SysRole> roles;

    public String getId() {
    return id;
    }

    public void setId(String id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getResourceType() {
    return resourceType;
    }

    public void setResourceType(String resourceType) {
    this.resourceType = resourceType;
    }

    public String getUrl() {
    return url;
    }

    public void setUrl(String url) {
    this.url = url;
    }

    public String getPermission() {
    return permission;
    }

    public void setPermission(String permission) {
    this.permission = permission;
    }

    public Long getParentId() {
    return parentId;
    }

    public void setParentId(Long parentId) {
    this.parentId = parentId;
    }

    public String getParentIds() {
    return parentIds;
    }

    public void setParentIds(String parentIds) {
    this.parentIds = parentIds;
    }

    public Boolean getAvailable() {
    return available;
    }

    public void setAvailable(Boolean available) {
    this.available = available;
    }

    public List<SysRole> getRoles() {
    return roles;
    }

    public void setRoles(List<SysRole> roles) {
    this.roles = roles;
    }
    }

UserRepository类

创建一个UserRepository用于查询用户信息:

1
2
3
4
5
public interface UserRepository extends CrudRepository<SysUser, String> {

//通过username查找用户信息;
SysUser findByUserName(String username);
}

插入数据

根据以上的代码会自动生成 sys_user(用户信息表)、sys_role(角色表)、sys_permission(权限表)、sys_user_role(用户角色表)、sys_role_permission(角色权限表)这五张表,为了方便测试我们给这五张表插入一些初始化数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
INSERT INTO `sys_user` (`id`,`user_name`,`name`,`pass_word`,`salt`,`state`) VALUES ('1', 'admin', '管理员', 'd3c59d25033dbf980d29554025c23a75', '8d78869f470951332959580424d4bf4f', 0);
INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (1,0,'用户管理',0,'0/','userInfo:view','menu','userInfo/userList');
INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (2,0,'用户添加',1,'0/1','userInfo:add','button','userInfo/userAdd');
INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (3,0,'用户删除',1,'0/1','userInfo:del','button','userInfo/userDel');
INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (1,0,'管理员','admin');
INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (2,0,'VIP会员','vip');
INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (3,1,'test','test');

INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (1,1);
INSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (2,1);
INSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (3,2);
INSERT INTO `sys_user_role` (`role_id`,`user_id`) VALUES (1,1);

Shiro 配置

  • ShiroConfig
    首先要配置的是 ShiroConfig 类,Apache Shiro 核心通过 Filter 来实现,就好像 SpringMvc 通过 DispachServlet 来主控制一样。Shiro 通过一系列filter来控制访问权限,并在它的内部为我们预先定义了多个过滤器,我们可以直接通过字符串配置这些过滤器。
    Filter Chain 定义说明:
    1、一个URL可以配置多个 Filter,使用逗号分隔
    2、当设置多个过滤器时,全部验证通过,才视为通过
    3、部分过滤器可指定参数,如 perms,roles
    常用的过滤器如下:
    authc:需要认证才能进行访问
    roles:有指定角色的用户可访问,通过[ ]指定具体角色,这里的角色名称与数据库中配置一致
    perms:有指定权限的用户可访问,通过[ ]指定具体权限,这里的权限名称与数据库中配置一致
    anon:所有用户可访问,通常作为指定页面的静态资源时使用
    user:配置记住我或认证通过可以访问
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    @Configuration
    public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {

    System.out.println("ShiroConfiguration.shirFilter()");
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    shiroFilterFactoryBean.setSecurityManager(securityManager);

    //shiro拦截器
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

    // 配置不被拦截的资源及链接 顺序判断
    filterChainDefinitionMap.put("/static/**", "anon");
    filterChainDefinitionMap.put("/favicon.ico", "anon");
    //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
    filterChainDefinitionMap.put("/logout", "logout");
    //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->: 这是一个坑呢,一不小心代码就不好使了;
    //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
    filterChainDefinitionMap.put("/**", "authc");
    // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
    shiroFilterFactoryBean.setLoginUrl("/login");
    // 登录成功后要跳转的链接
    shiroFilterFactoryBean.setSuccessUrl("/index");

    //未授权界面;
    shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactoryBean;
    }

    /**
    * 凭证匹配器
    * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
    * )
    *
    * @return
    */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
    HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
    hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
    return hashedCredentialsMatcher;
    }

    //自定义身份认证Realm(包含用户名密码校验,权限校验等)
    @Bean
    public MyShiroRealm myShiroRealm() {
    MyShiroRealm myShiroRealm = new MyShiroRealm();
    myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
    return myShiroRealm;
    }

    @Bean
    public SecurityManager securityManager() {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(myShiroRealm());
    return securityManager;
    }

    //开启shiro aop注解支持,不开启的话权限验证就会失效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
    }

    //配置异常处理,不配置的话没有权限后台报错,前台不会跳转到403页面
    @Bean(name = "simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver
    createSimpleMappingExceptionResolver() {
    SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
    Properties mappings = new Properties();
    mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
    mappings.setProperty("UnauthorizedException", "403");
    simpleMappingExceptionResolver.setExceptionMappings(mappings); // None by default
    simpleMappingExceptionResolver.setDefaultErrorView("error"); // No default
    simpleMappingExceptionResolver.setExceptionAttribute("ex"); // Default is "exception"
    return simpleMappingExceptionResolver;
    }
    }
  • 自定义Realm 类
    1、自定义一个 Realm 类,继承AuthorizingRealm 抽象类,重载 doGetAuthenticationInfo(),重写获取用户信息的方法。
    2、Shiro 的权限授权是通过继承AuthorizingRealm抽象类,重载doGetAuthorizationInfo();当访问到页面的时候,链接配置了相应的权限或者 Shiro 标签才会执行此方法否则不会执行,所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回 null 即可
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    public class MyShiroRealm extends AuthorizingRealm {

    @Resource
    private UserRepository userRepository;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    SysUser user = (SysUser) principals.getPrimaryPrincipal();
    for (SysRole role : user.getRoles()) {
    authorizationInfo.addRole(role.getRole());
    for (SysPermission permission : role.getPermissions()) {
    authorizationInfo.addStringPermission(permission.getPermission());
    }
    }
    return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
    throws AuthenticationException {
    System.out.println("MyShiroRealm.doGetAuthenticationInfo()");
    //获得当前用户的用户名
    String username = (String) token.getPrincipal();
    System.out.println(token.getCredentials());
    //根据用户名找到对象
    //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
    SysUser user = userRepository.findByUserName(username);
    // System.out.println("----->>userInfo=" + user);
    if (user == null) {
    return null;
    }
    //这里会去校验密码是否正确
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
    user, //用户名
    user.getPassWord(), //密码
    ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
    getName() //realm name
    );
    return authenticationInfo;
    }
    }

Controller类

  • 登录实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    @Controller
    public class LoginController {

    @GetMapping({"/", "/index"})
    public String index() {
    return "index";
    }

    @RequestMapping("/login")
    public String login(HttpServletRequest request, Map<String, Object> map) throws Exception {
    System.out.println("HomeController.login()");
    // 登录失败从request中获取shiro处理的异常信息。
    // shiroLoginFailure:就是shiro异常类的全类名.
    String exception = (String) request.getAttribute("shiroLoginFailure");
    String msg = "";
    //根据异常判断错误类型
    if (exception != null) {
    if (UnknownAccountException.class.getName().equals(exception)) {
    System.out.println("UnknownAccountException -- > 账号不存在:");
    msg = "UnknownAccountException -- > 账号不存在:";
    } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
    System.out.println("IncorrectCredentialsException -- > 密码不正确:");
    msg = "IncorrectCredentialsException -- > 密码不正确:";
    } else if ("kaptchaValidateFailed".equals(exception)) {
    System.out.println("kaptchaValidateFailed -- > 验证码错误");
    msg = "kaptchaValidateFailed -- > 验证码错误";
    } else {
    msg = "else >> " + exception;
    System.out.println("else -- >" + exception);
    }
    }
    map.put("msg", msg);
    // 此方法不处理登录成功,由shiro进行处理
    return "/login";
    }

    @RequestMapping("/403")
    public String unauthorizedRole() {
    System.out.println("------没有权限-------");
    return "/sys/403";
    }
    }
  • 权限测试类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    @Controller
    @RequestMapping("/user")
    public class UserController {
    /**
    * 用户查询.
    * @return
    */
    @RequestMapping("/userList")
    @RequiresPermissions("user:view")//权限管理;
    public String user(){
    return "user";
    }

    /**
    * 用户添加;
    * @return
    */
    @RequestMapping("/userAdd")
    @RequiresPermissions("user:add")//权限管理;
    public String userAdd(){
    return "userAdd";
    }

    /**
    * 用户删除;
    * @return
    */
    @RequestMapping("/userDel")
    @RequiresPermissions("user:del")//权限管理;
    public String userDel(){
    return "userDel";
    }
    }

    html页面

  • login.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
    <meta charset="UTF-8">
    <title>Login</title>
    </head>
    <body>
    错误信息:<h4 th:text="${msg}"></h4>
    <form action="" method="post">
    <p>账号:<input type="text" name="username" value="admin"/></p>
    <p>密码:<input type="text" name="password" value="123456"/></p>
    <p><input type="submit" value="登录"/></p>
    </form>
    </body>
    </html>
  • index.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
    <meta charset="UTF-8">
    <title>index</title>
    </head>
    <body>
    <h1>index</h1>
    <a href="/user/userList">用户列表</a>
    <a href="/user/userAdd">用户添加</a>
    <a href="/user/userDel">用户删除</a>
    <form th:action="@{/logout}" method="post">
    <p><input type="submit" value="注销"/></p>
    </form>
    </body>
    </html>
  • user.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>UserInfo</title>
    </head>
    <body>
    <h3>用户查询界面</h3>
    </body>
    </html>
  • userAdd.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Add</title>
    </head>
    <body>
    <h3>用户添加界面</h3>
    </body>
    </html>
  • userDel.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Del</title>
    </head>
    <body>
    <h3>用户删除界面</h3>
    </body>
    </html>
  • 403.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>403</title>
    </head>
    <body>
    <h3>403没有权限</h3>
    </body>
    </html>

欢迎关注我的其它发布渠道