平常我们做权限的时候会遇到这种情况:一个权限被多个角色拥有。比如我超级管理员可以添加用户,普通admin也可以添加用户,这是很正常很合理的。但是使用shiro的roles时有点小问题,下面测试一下:
新建一个JsonData类,用于规定返回的格式:
package com.example.demo.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author 黄豪琦
* 日期:2019-07-03 13:51
* 说明:用于返回
*/
@Data
public class JsonData implements Serializable {
private static final long serialVersionUID = 7983993295462511394L;
/**
* 1 成功 0:处理中 -1:失败
*/
private Integer code;
private Object data;
private String msg;
public JsonData() {
}
public JsonData(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public JsonData(Integer code, Object data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
}
public static JsonData success(){
return new JsonData(1, null, null);
}
public static JsonData success(Object data){
return new JsonData(1, data, null);
}
public static JsonData success(String msg){
return new JsonData(1, null, msg);
}
public static JsonData success(Object data, String msg){
return new JsonData(1, data, msg);
}
public static JsonData success(Integer code){
return new JsonData(code, null, null);
}
public static JsonData success(Integer code, Object data){
return new JsonData(code, data, null);
}
public static JsonData success(Integer code, String msg){
return new JsonData(code, null, msg);
}
public static JsonData success(Integer code, Object data, String msg){
return new JsonData(code, data, msg);
}
public static JsonData error(){
return new JsonData(-1, null, null);
}
public static JsonData error(String msg){
return new JsonData(-1, null, msg);
}
}
新增一个无权限跳转接口:
/**
* @author 黄豪琦
* 日期:2019-07-11 14:04
* 说明:
*/
@RequestMapping("/pub")
@RestController
public class PubController {
@GetMapping("/unauthorized")
public JsonData unauthorized(){
return JsonData.success("没有权限");
}
}
注意访问路径要和shiroConfig里配置的一样
添加一个拦截器:
可以看到我给这访问路径设置有两个角色可访问,设想中应该是只要拥有其中一个角色就可以访问。写个接口测试一下:
/**
* @author 黄豪琦
* 日期:2019-07-11 14:48
* 说明:
*/
@RequestMapping("/manage")
@RestController
public class ManageController {
@GetMapping("/roleTest")
public JsonData roleTest(){
return JsonData.success("访问成功");
}
}
数据库中显示刘备和赵云分别拥有root、admin角色:
启动项目,使用刘备登录:
访问显示没有权限:
之所以会这样是因为shiro自带的拦截器roles 规定的,如果配置了多个角色,那么就需要全部拥有这些角色;全局搜索DefaultFilter
按ctrl点进去查看
可以看到调用的是hasAllRoles,那么只要有一个角色没有就不会通过。
自定一个Role拦截器
在了解了原生role的原理后完全可以仿照它自己写一个拦截器来实现需求。
新建RoleOneAuthorizationFilter(名字越长越nb,按照shiro的风格来),继承AuthorizationFilter,然后要求实现一个方法,这个方法在用到这个拦截器时会执行,返回false表示自己已处理,返回true表示继续往下执行。 然后直接把RolesAuthorizationFilter中的复制过来改一改就可以了。
/**
* @author 黄豪琦
* 日期:2019-07-11 15:16
* 说明:自定义role拦截器
*/
public class RoleOneAuthorizationFilter extends AuthorizationFilter {
public RoleOneAuthorizationFilter(){}
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = this.getSubject(request, response);
//获取当前路径所需要的角色
String[] rolesArray = (String[])mappedValue;
//如果有配置,那说明对角色有要求
if (rolesArray != null && rolesArray.length != 0) {
Set<String> roles = CollectionUtils.asSet(rolesArray);
boolean flat = false;
for(String item : roles){
//判断是否有这个角色
if(subject.hasRole(item)){
flat = true;
}
}
return flat;
} else {
return true;
}
}
}
将自定义的filter添加到拦截器工厂中去:
然后在过滤链中修改
重启项目再访问: