写在前面

前面我们使用SpringBoot集成Shiro搭建了一个简易的权限管理系统,但是那种在实际开发过程中用的不多,本篇来学习另一种较为常见的SpringBoot集成Shiro搭建权限管理系统,这里就不使用Thymeleaf模板引擎,而是直接返回RESTful风格的API。

新建SpringBoot项目

使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为shiro-swagger,然后在pom.xml文件中添加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
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--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>
<!--JDBC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!-- shiro 关键包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--添加数据库连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.25</version>
</dependency>

<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<!-- swagger生成接口API -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- 接口API生成html文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>

DataSource配置

application.properties配置文件中配置DataSource的基本信息,代码如下所示:

1
2
3
4
5
# 数据库相关配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shiroswagger?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=envy123

JPA配置

application.properties配置文件中配置JPA的基本信息,代码如下所示:

1
2
3
4
5
6
7
8
9
# JPA相关配置
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

spring.main.allow-bean-definition-overriding=true

spring.aop.proxy-target-class=true

其他信息配置

application.properties配置文件中配置其他信息,代码如下所示:

1
2
3
4
5
# Swagger配置
swagger.enabled=true

server.port=8080
server.servlet.context-path=/shiro

创建实体类

新建entity包,并在其中创建三个实体类:User、Role和Permission,各个实体类中的代码如下所示:
首先看一下用户信息表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//User.java

@Data
@Entity
public class User {
@Id
private Integer userId; //主键

@Column(unique = true)
private String username; //登录账户,注意值唯一

private String name; //名称,(匿名或者真实姓名)

private String password; //密码

private String salt; //密码加密的盐

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role",
joinColumns = {@JoinColumn(name = "USER_ID",referencedColumnName = "userId")},
inverseJoinColumns = {@JoinColumn(name = "ROLE_ID",referencedColumnName = "roleId")}
)
private Set<Role>roles; //用户角色
}

再来看一下角色信息表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Role.java

@Data
@Entity
public class Role {
@Id
@GeneratedValue
private Long roleId; //主键

private String name; //角色名称,如admin/user

private String description; //角色描述,注意这是用于UI显示用的

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "role_permission",
joinColumns = {@JoinColumn(name = "ROLE_ID",referencedColumnName = "roleId")},
inverseJoinColumns = {@JoinColumn(name = "PERMISSION_ID",referencedColumnName = "permissionId")}
)
private Set<Permission> permissions; //角色权限
}

再来看一下权限信息表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Permission.java

@Data
@Entity
public class Permission {
@Id
private Integer permissionId; //主键

private String name; //权限名称,如user:add/user:delete

private String description; //权限描述,注意这是用于UI显示用的

private String url; //权限地址
}

插入数据

在数据库中新建shiroswagger数据库,然后启动项目,此时会在数据库中自动生成user(用户表)、role(角色表)、permission(权限表)、user_role(用户角色表)和role_permission(角色权限表),为了后续测试需要,这里先往这些表中插入一些测试数据,如下所示:

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use shiroswagger;


SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for hibernate_sequence
-- ----------------------------
DROP TABLE IF EXISTS `hibernate_sequence`;
CREATE TABLE `hibernate_sequence` (
`next_val` bigint(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of hibernate_sequence
-- ----------------------------
INSERT INTO `hibernate_sequence` VALUES ('1');

-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`permission_id` int(11) NOT NULL,
`description` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES ('1', '增加用户', 'user:add', '/save');
INSERT INTO `permission` VALUES ('2', '删除用户', 'user:delete', '/delete');
INSERT INTO `permission` VALUES ('3', '修改用户', 'user:edit', '/update');
INSERT INTO `permission` VALUES ('4', '查询用户', 'user:query', '/select');

-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`role_id` bigint(20) NOT NULL,
`description` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', '开发', 'develop');
INSERT INTO `role` VALUES ('2', '测试', 'test');
INSERT INTO `role` VALUES ('3', '运维', 'operate');

-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`role_id` bigint(20) NOT NULL,
`permission_id` int(11) NOT NULL,
PRIMARY KEY (`role_id`,`permission_id`),
KEY `FKf8yllw1ecvwqy3ehyxawqa1qp` (`permission_id`),
CONSTRAINT `FKa6jx8n8xkesmjmv6jqug6bg68` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`),
CONSTRAINT `FKf8yllw1ecvwqy3ehyxawqa1qp` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES ('1', '1');
INSERT INTO `role_permission` VALUES ('2', '1');
INSERT INTO `role_permission` VALUES ('1', '2');
INSERT INTO `role_permission` VALUES ('1', '3');
INSERT INTO `role_permission` VALUES ('2', '3');
INSERT INTO `role_permission` VALUES ('1', '4');
INSERT INTO `role_permission` VALUES ('2', '4');
INSERT INTO `role_permission` VALUES ('3', '4');

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`user_id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`salt` varchar(255) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `UK_sb8bbouer5wak8vyiiy4pf2bx` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '架构师', 'cd874e3957efc155e0d4380866e024be', 'gakMCJgWgfIGTimgD2l/bw==', 'admin');
INSERT INTO `user` VALUES ('2', '前端测试', 'cd874e3957efc155e0d4380866e024be', 'gakMCJgWgfIGTimgD2l/bw==', 'envy');
INSERT INTO `user` VALUES ('3', '网络管理', 'cd874e3957efc155e0d4380866e024be', 'gakMCJgWgfIGTimgD2l/bw==', 'hello');

-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`user_id` int(11) NOT NULL,
`role_id` bigint(20) NOT NULL,
PRIMARY KEY (`user_id`,`role_id`),
KEY `FKa68196081fvovjhkek5m97n3y` (`role_id`),
CONSTRAINT `FK859n2jvi8ivhui0rl0esws6o` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`),
CONSTRAINT `FKa68196081fvovjhkek5m97n3y` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES ('1', '1');
INSERT INTO `user_role` VALUES ('2', '2');
INSERT INTO `user_role` VALUES ('3', '3');

创建Repository层

新建repository包,并在其中创建三个接口文件UserRepository、RoleRepository和PermissionRoleRepository,各个接口中的文件如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//UserRepository.java
public interface UserRepository extends JpaRepository<User,Integer> {
/**
* 通过用户名查找用户信息
* */
public User findByUsername(String username);
}


//RoleRepository.java
public interface RoleRepository extends JpaRepository<Role,Integer> {
}


//PermissionRoleRepository
public interface PermissionRoleRepository extends JpaRepository<Permission,Integer> {
}

创建Service层

新建service包,并在其中创建一个接口文件UserService:

1
2
3
4
5
6
public interface UserService {
/**
* 通过用户名查找用户信息
* */
User findByUsername(String username);
}

之后在service包内新建一个impl包,并在impl包内新建一个UserServiceImpl类:

1
2
3
4
5
6
7
8
9
10
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;

@Override
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
}

自定义Realm

新建realm包,并在其中创建一个MyShiroRealm类,其中的代码如下所示:

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
@Component
public class MyShiroRealm extends AuthorizingRealm {

@Autowired
private UserService userService;

//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1、获取用户身份,这里是username
String username = (String) authenticationToken.getPrincipal();
//2、通过username去数据库中查询用户
User user = userService.findByUsername(username);
//3、如果用户不存在,则抛出用户不存在这一异常
if(user ==null){
throw new UnknownAccountException("用户名或者密码错误");
}
//4、用户存在,则根据用户信息来构建一个AuthenticationInfo对象,通常使用它的实现类SimpleAuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
username, //登录账户,注意值唯一,注意这个就是后续doGetAuthorizationInfo中的principalCollection对象,如果设置为user,那么后期就是user
user.getPassword(), //密码
ByteSource.Util.bytes(user.getSalt()), //盐=密码+盐
getName()); //realm的值,此处为自定义的MyShiroRealm
return simpleAuthenticationInfo;
}

//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//认证通过后,接下来开始授权操作
//1、从 PrincipalCollection中获取登录用户的信息
String username = (String) principalCollection.getPrimaryPrincipal();
User user = userService.findByUsername(username);
//2、新建一个授权对象
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//3、遍历用户,并添加角色和权限
for(Role role:user.getRoles()){
simpleAuthorizationInfo.addRole(role.getName());
for(Permission permission:role.getPermissions()){
simpleAuthorizationInfo.addStringPermission(permission.getName());
}
}
return simpleAuthorizationInfo;
}
}

Shiro配置

新建config包,并在其中创建一个ShiroConfig类,其中的代码如下所示:

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
105
106
107
108
@Configuration
public class ShiroConfig {

/**
* 密码加密设置,注意密码加密校验由SimpleAuthenticationInfo负责
* */
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
System.out.println("******hashedCredentialsMatcher******");
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5"); //设置加密算法,这里使用MD5算法
matcher.setHashIterations(3); //加密次数,这里设置三次,其实相当于md5(md5(md5()))
return matcher;
}

/**
* 返回自定义MyShiroRealm
* */
@Bean
public MyShiroRealm myShiroRealm(){
System.out.println("******myShiroRealm******");
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}

/**
* 返回SecurityManager对象
* */
@Bean
public SecurityManager securityManager(){
System.out.println("******securityManager******");
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//将自定义的Realm注册进去
securityManager.setRealm(myShiroRealm());
securityManager.setRememberMeManager(null);
return securityManager;
}

@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
System.out.println("******shiroFilter******");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);

//设置未登录时候的路径

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

//配置不会被拦截的链接,此时会按照顺序进行判断
//anon是匿名访问,authc是通过认证后才能访问
filterChainDefinitionMap.put("/login","anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/druid/**", "anon");
filterChainDefinitionMap.put("/sys/login", "anon");
filterChainDefinitionMap.put("/swagger/**", "anon");
filterChainDefinitionMap.put("/v2/api-docs", "anon");
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger-resources/**", "anon");
filterChainDefinitionMap.put("/doc.html", "anon");

//配置退出过滤器,具体已经由Shiro实现了
filterChainDefinitionMap.put("/logout","logout");

//配置过滤链,它会从上到下顺序执行,因此一般将/**放在最下面,
//表示出了上面的配置,剩下的全部路径都需要经过认证后才能访问
filterChainDefinitionMap.put("/**","authc");

//设置未授权页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}

/**
* 配置SecurityManager的生命周期处理器
*/
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}

/**
* 开启Shiro注解支持
* 这样就可以使用@RequiresRoles和@RequirePermissions
*/
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
System.out.println("******DefaultAdvisorAutoProxyCreator******");

DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}

/**
* 开启Shiro AOP注解支持
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
System.out.println("******AuthorizationAttributeSourceAdvisor******");
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}

Swagger配置

在config包内创建一个SwaggerConfig类,其中的代码如下所示:

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
@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
//是否开启swagger,正式环境一般是需要关闭的,可根据springboot的多环境配置进行设置
@Value(value = "${swagger.enabled}")
Boolean swaggerEnabled;

@Bean
Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
//是否开启
.enable(swaggerEnabled).select()
//扫描的路径包
.apis(RequestHandlerSelectors.basePackage("com.envy.shiroswagger"))
// 指定路径处理PathSelectors.any()代表所有的路径
.paths(PathSelectors.any())
.build().apiInfo(
new ApiInfoBuilder().description("SpringBoot+Shiro搭建权限系统接口测试文档").contact(
new Contact("余思博客","https://github.com/envythink","envyzhan@aliyun.com"))
.version("v1.0")
.title("API测试文档")
.license("Apache2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSe-2.0")
.build()
);
}

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 解决静态资源无法访问
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
// 解决swagger无法访问
registry.addResourceHandler("/swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
// 解决swagger的js文件无法访问
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}

创建Controller层

新建controller包,并在其中创建UserController类,其中的代码如下所示:

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
@RestController
public class UserController {

@ApiOperation(value = "登录",notes = "参数:用户名 密码")
@PostMapping("/login")
public Map<String,Object> login(String username,String password){
Map<String,Object> map = new HashMap<>();
Subject subject = SecurityUtils.getSubject();
//用户未认证,那么需要认证
if(!subject.isAuthenticated()){
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try{
subject.login(token);
map.put("status",200);
}catch (AuthenticationException e){
map.put("status",401);
map.put("msg","登录失败");
System.out.println("登录失败:"+e.getMessage());
}
}
return map;
}

@ApiOperation(value = "登出",notes = "参数:无")
@GetMapping("/logout")
public Map<String,Object> logout(){
Map<String,Object> map = new HashMap<>();
Subject subject = SecurityUtils.getSubject();
subject.logout();
map.put("status",200);
return map;
}

@ApiOperation(value = "无权限",notes = "参数:无")
@GetMapping("/unauthorized")
public Map<String,Object> unauthorized(){
Map<String,Object> map = new HashMap<>();
map.put("status",404);
map.put("msg","无权限");
return map;
}

@ApiOperation(value = "未登录",notes = "参数:无")
@GetMapping("/unLogin")
public Map<String,Object> unLogin(){
Map<String,Object> map = new HashMap<>();
map.put("status",404);
map.put("msg","未登录");
return map;
}
}

再来创建一个TestController类,其中的代码如下所示:

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
@RequestMapping("/test")
@RestController
public class TestController {

/**
* 模拟添加用户
* */
@RequiresPermissions({"user:add"})
@PostMapping("/save")
public Map<String,Object> save(){
System.out.println("******save******");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("msg","当前用户具有添加用户的权限");
return map;
}

/**
* 模拟删除用户
* */
@RequiresPermissions({"user:delete"})
@DeleteMapping("/delete")
public Map<String,Object> delete(){
System.out.println("******delete******");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("msg","当前用户具有删除用户的权限");
return map;
}

/**
* 模拟修改用户
* */
@RequiresPermissions({"user:edit"})
@PostMapping("/update")
public Map<String,Object> update(){
System.out.println("******update******");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("msg","当前用户具有修改用户的权限");
return map;
}

/**
* 模拟查询用户
* */
@RequiresPermissions({"user:query"})
@GetMapping("/select")
public Map<String,Object> select(){
System.out.println("******select******");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("msg","当前用户具有查询用户的权限");
return map;
}

/**
* 判断当前用户是否具有开发人员角色
* */
@RequiresRoles({"develop"})
@GetMapping("/develop")
public Map<String,Object> develop(){
System.out.println("******develop******");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("msg","当前用户具有开发人员角色");
return map;
}

/**
* 判断当前用户是否具有开发测试角色
* */
@RequiresRoles({"test"})
@GetMapping("/test")
public Map<String,Object> test(){
System.out.println("******test******");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("msg","当前用户具有测试人员角色");
return map;
}

/**
* 判断当前用户是否具有运维人员角色
* */
@RequiresRoles({"operate"})
@GetMapping("/operate")
public Map<String,Object> operate(){
System.out.println("******operate******");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("msg","当前用户具有运维人员角色");
return map;
}
}

启动并测试

启动ShiroSwaggerApplication项目入口类,然后在浏览器中访问http://localhost:8080/shiro/swagger-ui.html链接时,页面会显示如下信息:

之后查看这个两个Controller中的方法,如下所示:

接下来开始测试,依次如下所示:
(1)登录成功时:

(2)登录失败时:

(3)当前用户具有某个角色时:

(4)当前用户没有某个角色时:

(5)当前用户具有某个权限时:

(6)当前用户没有某个权限时:

这样关于SpringBoot+Shiro搭建RESTful风格权限系统的学习就到此为止,注意上述这种方式并不适合前后端分离的情况,关于前后端分离的情况将会在后续文章中进行学习。