权限校验
在通用的权限管理中,会出现用户、角色、权限三个表,并且设置大多保存菜单列表给前端,如果将粒度改为按钮级别,表中的数据是很多的,每次查询都要关联到很多数据
虽然三者的关系看似多对多(表设计),其实在真正应用时会发现,一个用户进入系统只会选择一个角色,而一个角色对应的也只有一套权限,从这个大方向上看,三者的关系是单一的
那么要做到细粒度的权限控制,只需要规定好每个接口都需要一个权限值,而每个角色能拥有某些权限值,一个用户绑定一个角色即可
实现的方案就是,可以将其表设计简化,大体用户、角色、权限关系模型依然没有变,但是可以将每个接口规定一个权限值(数字),并直接放在角色表中即可,大大简化了复杂度,session中不在缓存那么多数据(session数据量大也会耗内存)
实现方式
定义一个权限列表注解类
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Auth {
int keyType();
/**
* 登录后的权限
*/
int AUTH_COMMON_LOGIN = 100;
/**
* 测试接口权限
*/
int AUTH_COMMON_TEST = 101;
}
定义拦截器拦截权限
**
* 请求拦截
*/
public class ReqInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1.通过session或toten拿到用户角色(ID或名称)
// 2.通过角色在缓存或数据库中拿到角色对应的权限值(字符)
// 3.拿到接口所需要的权限值
HandlerMethod handlerMethod = (HandlerMethod) handler;
Auth auth = handlerMethod.getMethodAnnotation(Auth.class);
// 判断权限值是否包含了接口所需要的值
if (auths.contains(String.valueOf(auth.keyType()))) {
// 有权限放行
return true;
}
// 没有权限不放行并设置一个状态码给前端做判断
response.setStatus(500);
return false;
}
}
使用方式,在接口上加权限注解
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping("say")
@Auth(keyType = Auth.AUTH_COMMON_TEST)
public R<String> test(@RequestBody JSONObject params) {
System.out.println(params);
return R.ok("测试成功");
}
}
复杂业务
有这样一个场景,例如公告管理接口,公告存在于不同的版块中,这对于接口端来说就是一个字段的区别,但是在前端,不同的模块放在了不同的地方,并且对于不同的角色看到的模块不一样,如果基于接口来做的权限,也就是这个接口是否有权访问,如果这个接口有权访问,那么所有模块都有权访问,这不符合需求,如果再写一个接口(就是同样的代码),这就是低级程序员干的事,所以现在需要实现的是接口与权限的一对多关系
使用上面的方式做的权限校验可以轻松的实现
调整注解类
int[] keyType();
使用的时候指定多个权限
@Auth(keyType = {Auth.AUTH_COMMON_NOTICE_LIST,Auth.AUTH_COMMON_LOGIN})
调整拦截器的auth.keyType()
,因为此时是个数组