数据库

新建数据库

数据库命名为 db_shiro,可以直接导入我的数据库文件,那么就不需要查看下面的数据库操作了,sql文件地址为:a6678696/ShiroDemo: Spring Boot整合Shiro实现认证和授权 (github.com)

新建五张表

t_user用户表

t_user_role用户角色表

t_role为角色表

t_role_permission用户权限表

t_permission权限表

插入数据

t_user用户表

1
insert  into `t_user`(`id`,`userName`,`password`,`nickName`,`salt`) values (1,'ledao','8b8d72a8743e5102087b7d3e0423a729','乐道','gQKQEpNUeNhRDiGsd3RYqA=='),(2,'admin','838f8ca3ba499ede3585cddcb4d72f05','小明','uDCwdPYvZmym7WBNvsgh4Q==');

t_user_role用户角色表

1
insert  into `t_user_role`(`id`,`roleId`,`userId`) values (1,1,2),(2,2,2),(3,2,1);

t_role角色表

1
insert  into `t_role`(`id`,`role`) values (1,'管理员'),(2,'教师');

t_role_permission用户权限表

1
insert  into `t_role_permission`(`id`,`roleId`,`permissionId`) values (1,1,1),(2,2,1),(3,1,2);

t_permission权限表

1
insert  into `t_permission`(`id`,`permission`) values (1,'添加学生'),(2,'添加教师');

表之间的关联

如果要查询某个用户拥有的所有权限,可以先根据用户的id获取该用户的所有角色(用户和角色是一对多的关系,即:一个用户可以拥有0个或多个角色),然后再根据角色的id获取该角色的权限(角色和权限是一对多的关系,即:一个角色可以拥有0个或多个权限),最后该用户的全部权限为:该用户的所有角色对应权限的集合

实现过程

项目结构

启动类添加注解

添加注解 @MapperScan(“com.ledao.mapper”) ,路径为存放Mapper接口的包

application.yml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
server:
port: 80
servlet:
context-path: /

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/db_shiro?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8
thymeleaf:
cache: false

pom.xml依赖配置

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
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

实体类

User.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
package com.ledao.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
* 用户实体类
*
* @author LeDao
* @company
* @create 2021-09-16 11:03
*/
@Data
@TableName(value = "t_user")
public class User {

/**
* 编号
*/
@TableId
private Integer id;

/**
* 用户名
*/
@TableField(value = "userName")
private String userName;

/**
* 密码
*/
private String password;

/**
* 盐值
*/
private String salt;

/**
* 昵称
*/
@TableField(value = "nickName")
private String nickName;
}

UserRole.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
package com.ledao.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
* 用户角色实体
* 用于绑定用户和角色,即:某个用户有什么角色
*
* @author LeDao
* @company
* @create 2021-09-16 11:15
*/
@Data
@TableName(value = "t_user_role")
public class UserRole {

/**
* 编号
*/
@TableId
private Integer id;

/**
* 用户id
*/
@TableField(value = "userId")
private Integer userId;

/**
* 角色id
*/
@TableField(value = "roleId")
private Integer roleId;
}

Role.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
package com.ledao.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
* 角色实体类
*
* @author LeDao
* @company
* @create 2021-09-16 11:12
*/
@Data
@TableName(value = "t_role")
public class Role {

/**
* 编号
*/
@TableId
private Integer id;

/**
* 角色名称
*/
private String role;
}

RolePermission.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
package com.ledao.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
* 角色权限实体类
* 用于绑定角色和权限,即:某个角色有什么权限
*
* @author LeDao
* @company
* @create 2021-09-16 11:19
*/
@Data
@TableName(value = "t_role_permission")
public class RolePermission {

/**
* 编号
*/
@TableId
private Integer id;

/**
* 角色id
*/
@TableField(value = "roleId")
private Integer roleId;

/**
* 权限id
*/
@TableField(value = "permissionId")
private Integer permissionId;
}

Permission.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
package com.ledao.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
* 权限实体类
*
* @author LeDao
* @company
* @create 2021-09-16 11:18
*/
@Data
@TableName(value = "t_permission")
public class Permission {

/**
* 编号
*/
@TableId
private Integer id;

/**
* 权限名称
*/
private String permission;
}

Mapper接口

UserMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.ledao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ledao.entity.User;

/**
* @author LeDao
* @company
* @create 2021-09-16 11:46
*/
public interface UserMapper extends BaseMapper<User> {
}

UserRoleMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.ledao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ledao.entity.UserRole;

/**
* @author LeDao
* @company
* @create 2021-09-16 11:48
*/
public interface UserRoleMapper extends BaseMapper<UserRole> {
}

RoleMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.ledao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ledao.entity.Role;

/**
* @author LeDao
* @company
* @create 2021-09-16 11:47
*/
public interface RoleMapper extends BaseMapper<Role> {
}

RolePermissionMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.ledao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ledao.entity.RolePermission;

/**
* @author LeDao
* @company
* @create 2021-09-16 11:49
*/
public interface RolePermissionMapper extends BaseMapper<RolePermission> {
}

PermissionMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.ledao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ledao.entity.Permission;

/**
* @author LeDao
* @company
* @create 2021-09-16 11:49
*/
public interface PermissionMapper extends BaseMapper<Permission> {
}

Service接口

UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.ledao.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ledao.entity.User;

/**
* @author LeDao
* @company
* @create 2021-09-16 11:56
*/
public interface UserService extends IService<User> {

/**
* 根据用户名获取用户信息
*
* @param userName
* @return
*/
User findByUserName(String userName);
}

UserRoleService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.ledao.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ledao.entity.User;
import com.ledao.entity.UserRole;

import java.util.List;

/**
* @author LeDao
* @company
* @create 2021-09-16 12:52
*/
public interface UserRoleService extends IService<UserRole> {

/**
* 根据用户id获取用户的角色
*
* @param userId
* @return
*/
List<UserRole> findByUserId(Integer userId);
}

RoleService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.ledao.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ledao.entity.Role;

/**
* @author LeDao
* @company
* @create 2021-09-16 12:59
*/
public interface RoleService extends IService<Role> {

/**
* 根据id获取角色
*
* @param id
* @return
*/
Role findById(Integer id);
}

RolePermissionService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.ledao.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ledao.entity.RolePermission;

import java.util.List;

/**
* @author LeDao
* @company
* @create 2021-09-16 13:08
*/
public interface RolePermissionService extends IService<RolePermission> {

/**
* 根据角色id获取该角色的所有权限
*
* @param roleId
* @return
*/
List<RolePermission> findByRoleId(Integer roleId);
}

PermissionService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.ledao.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ledao.entity.Permission;

/**
* @author LeDao
* @company
* @create 2021-09-16 13:41
*/
public interface PermissionService extends IService<Permission> {

/**
* 根据id获取权限
*
* @param id
* @return
*/
Permission findById(Integer id);
}

Service接口实现类

UserServiceImpl.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
package com.ledao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ledao.entity.User;
import com.ledao.mapper.UserMapper;
import com.ledao.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
* @author LeDao
* @company
* @create 2021-09-16 11:59
*/
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

@Resource
private UserMapper userMapper;

@Override
public User findByUserName(String userName) {
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("userName", userName);
return userMapper.selectOne(userQueryWrapper);
}
}

UserRoleServiceImpl.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
package com.ledao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ledao.entity.UserRole;
import com.ledao.mapper.UserRoleMapper;
import com.ledao.service.UserRoleService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
* @author LeDao
* @company
* @create 2021-09-16 12:54
*/
@Service("userRoleService")
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper,UserRole> implements UserRoleService {

@Resource
private UserRoleMapper userRoleMapper;

@Override
public List<UserRole> findByUserId(Integer userId) {
QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
userRoleQueryWrapper.eq("userId", userId);
return userRoleMapper.selectList(userRoleQueryWrapper);
}
}

RoleServiceImpl.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
package com.ledao.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ledao.entity.Role;
import com.ledao.mapper.RoleMapper;
import com.ledao.service.RoleService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
* @author LeDao
* @company
* @create 2021-09-16 13:00
*/
@Service("roleService")
public class RoleServiceImpl extends ServiceImpl<RoleMapper,Role> implements RoleService {

@Resource
private RoleMapper roleMapper;

@Override
public Role findById(Integer id) {
return roleMapper.selectById(id);
}
}

RolePermissionServiceImpl.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
package com.ledao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ledao.entity.RolePermission;
import com.ledao.mapper.RolePermissionMapper;
import com.ledao.service.RolePermissionService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
* @author LeDao
* @company
* @create 2021-09-16 13:11
*/
@Service("rolePermissionService")
public class RolePermissionServiceImpl extends ServiceImpl<RolePermissionMapper,RolePermission> implements RolePermissionService {

@Resource
private RolePermissionMapper rolePermissionMapper;

@Override
public List<RolePermission> findByRoleId(Integer roleId) {
QueryWrapper<RolePermission> rolePermissionQueryWrapper = new QueryWrapper<>();
rolePermissionQueryWrapper.eq("roleId", roleId);
return rolePermissionMapper.selectList(rolePermissionQueryWrapper);
}
}

PermissionServiceImpl.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
package com.ledao.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ledao.entity.Permission;
import com.ledao.mapper.PermissionMapper;
import com.ledao.service.PermissionService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
* @author LeDao
* @company
* @create 2021-09-16 13:41
*/
@Service("permissionService")
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper,Permission> implements PermissionService {

@Resource
private PermissionMapper permissionMapper;

@Override
public Permission findById(Integer id) {
return permissionMapper.selectById(id);
}
}

自定义Realm

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
92
93
94
95
96
97
98
99
100
101
package com.ledao.realm;

import com.ledao.entity.*;
import com.ledao.service.*;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import javax.annotation.Resource;
import java.util.List;

/**
* 自定义Realm
*
* @author LeDao
* @company
* @create 2021-09-16 11:44
*/
public class MyShiroRealm extends AuthorizingRealm {

@Resource
private UserService userService;

@Resource
private UserRoleService userRoleService;

@Resource
private RoleService roleService;

@Resource
private RolePermissionService rolePermissionService;

@Resource
private PermissionService permissionService;

/**
* 授权
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//获取已登录用户的用户名
String userName = (String) principalCollection.getPrimaryPrincipal();
//控制台打印用户名
System.out.println(userName);
//获取用户的id
Integer userId = userService.findByUserName(userName).getId();
//查询该用户的所有角色
List<UserRole> userRoleList = userRoleService.findByUserId(userId);
//如果该用户拥有角色
if (userRoleList.size() > 0) {
for (UserRole userRole : userRoleList) {
//获取当前角色实体
Role role = roleService.findById(userRole.getRoleId());
//向Shiro添加角色的名称
simpleAuthorizationInfo.addRole(role.getRole());
//控制台打印角色的名称
System.out.println(role.getRole());
//获取该角色的全部权限
List<RolePermission> rolePermissionList = rolePermissionService.findByRoleId(role.getId());
if (rolePermissionList.size() > 0) {
for (RolePermission rolePermission : rolePermissionList) {
//获取当前权限实体
Permission permission = permissionService.findById(rolePermission.getPermissionId());
//向Shiro添加权限的名称
simpleAuthorizationInfo.addStringPermission(permission.getPermission());
//控制台打印权限的名称
System.out.println(permission.getPermission());
}
}
}
}
return simpleAuthorizationInfo;
}

/**
* 认证
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String userName = (String) authenticationToken.getPrincipal();
User user = userService.findByUserName(userName);
if (user != null) {
return new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), getName());
} else {
return null;
}
}
}

Shiro配置

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
92
93
94
95
96
97
98
99
100
101
102
103
104
package com.ledao.config;

import com.ledao.realm.MyShiroRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.HashMap;
import java.util.Map;

/**
* Shiro配置
*
* @author LeDao
* @company
* @create 2021-09-16 14:09
*/
@Configuration
public class ShiroConfig {

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

shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}

/**
* 定义自己的Realm
*
* @return
*/
@Bean
public MyShiroRealm myShiroRealm() {
return new MyShiroRealm();
}

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

/**
* Shiro生命周期处理器
*
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}

/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
*
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}

@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}

Controller类

IndexController.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
package com.ledao.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
* @author LeDao
* @company
* @create 2021-09-16 14:19
*/
@Controller
public class IndexController {

/**
* 首页
*
* @return
*/
@RequestMapping({"/", "/index"})
public ModelAndView index() {
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
return mav;
}

/**
* 跳转到登录页面
*
* @return
*/
@RequestMapping("/toLoginPage")
public ModelAndView toLoginPage() {
ModelAndView mav = new ModelAndView();
mav.setViewName("login");
return mav;
}
}

UserController.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package com.ledao.controller;

import com.ledao.entity.User;
import com.ledao.service.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

/**
* @author LeDao
* @company
* @create 2021-09-16 19:32
*/
@Controller
@RequestMapping("/user")
public class UserController {

@Resource
private UserService userService;

/**
* 登录
*
* @param user
* @param session
* @return
*/
@RequestMapping("/login")
public ModelAndView login(User user, HttpSession session) {
ModelAndView mav = new ModelAndView();
User currentUser = userService.findByUserName(user.getUserName());
if (currentUser != null) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), getEncodePassword("md5", user.getPassword(), currentUser.getSalt(), 2));
try {
subject.login(token);
session.setAttribute("currentUser", currentUser);
mav.setViewName("index");
} catch (AuthenticationException e) {//登录失败
e.printStackTrace();
mav.addObject("error", "用户名或密码错误!!");
mav.addObject("user", user);
mav.setViewName("login");
}
} else {//用户不存在
mav.addObject("error", "用户名或密码错误!!");
mav.addObject("user", user);
mav.setViewName("login");
}
return mav;
}

/**
* 添加学生
*
* @return
*/
@ResponseBody
@RequestMapping("/addStudent")
@RequiresPermissions(value = "添加学生")
public String addStudent() {
return "添加学生成功";
}

/**
* 添加教师
*
* @return
*/
@ResponseBody
@RequestMapping("/addTeacher")
@RequiresPermissions(value = "添加教师")
public String addTeacher() {
return "添加教师成功";
}

/**
* 获取md5加密后的密码
*
* @param encryptName 加密算法名称
* @param password 加密前的密码
* @param salt 盐值
* @param times 加密次数
* @return
*/
private static String getEncodePassword(String encryptName, String password, String salt, Integer times) {
return new SimpleHash(encryptName, password, salt, times).toString();
}
}

HTML页面

login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<form action="/user/login" method="post" style="width: 40%;margin-left: 27%;margin-top: 8%">
<h1 style="text-align: center">登录</h1>
<div class="form-group">
<label for="userName">用户名</label>
<input type="text" id="userName" name="userName" class="form-control" th:value="${user==null?'':user.userName}">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="text" id="password" name="password" class="form-control" th:value="${user==null?'':user.password}">
</div>
<input type="submit" value="提交" class="btn btn-primary"><span style="color: red" th:text="${error}"></span>
</form>
</body>
</html>

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<h1 style="text-align: center">首页</h1>
<h4 style="text-align: center">
当前用户:<span th:text="${session.currentUser.nickName}"></span>
</h4>
<div style="text-align: center">
<a href="/logout"><button type="button" class="btn btn-danger">注销登录</button></a>
<a href="/user/addTeacher"><button type="button" class="btn btn-primary">添加教师</button></a>
<a href="/user/addStudent"><button type="button" class="btn btn-info">添加学生</button></a>
</div>
</body>
</html>

测试

运行项目后,在浏览器地址栏输入:localhost/index ,无法访问首页会直接重定向到 localhost/toLoginPage ,这是因为此时没有登录所以不能访问首页

登录成功后,即可进入首页

数据库中有两个用户,用户一:用户名leadao密码123456,用户二:用户名admin密码admin

用户一只有添加学生的权限,所以可以添加学生,但是添加教师时会报错

用户二有添加学生和添加教师的权限,所以可以添加学生和教师

用户一和用户二都可以注销登录

GitHub地址

本例子的GitHub地址为:a6678696/ShiroDemo: Spring Boot整合Shiro实现认证和授权 (github.com)