上篇文章说了AOP实现上下文的存储,有需要的可以看看,
环境需求:springboot + mysql 5.7.16 + Lombok 1.18.12
1、需求背景
为了实现不同的客户群体,看到的管理系统菜单目录不同,所以要给他们分配不同的权限,比如校长可以给老师分配不同的课程,学生只可以访问课程不可以修改课程,老师不光可以访问课程,还可以修改和新增课程。
上面只是举个例子,总之核心就是为了实现,不同的角色只能使用相对应的功能,各自分工不同。
2、功能实现
表单设计:角色表,用户表,权限表。
用户表user_auth:id,delete_id ,name,工号,role_id
角色表role_auth:id,delete_id,角色name,权限等级(lv0,lv1,lv2,common)。
路径表auth_source:id,delete_id, front_source,source_name,url(后端url用,隔开,可以匹配*号),parent_id,source_level,external_id(用于扩展的外部资源)
mysql> create table user_auth( -> id int AUTO_INCREMENT, -> delete_id int comment '默认0,删除改为当前id', -> user_id varchar(32) comment '工号', -> user_name varchar(32) comment '姓名', -> role_id int comment '角色id', -> primary key(id) -> )engine=InnoDB charset=utf8 row_format=dynamic; Query OK, 0 rows affected (0.05 sec) mysql> create table role_auth( -> id int auto_increment, -> delete_id int comment '默认0,删除改为当前id', -> role_name varchar(32) comment '角色名称', -> level varchar(32) comment '权限等级:lv0最高,lv1次之,common通用', -> primary key(id) -> )engine=InnoDB charset=utf8 row_format=dynamic; Query OK, 0 rows affected (0.04 sec) mysql> create table auth_source( -> id int auto_increment, -> delete_id int comment '默认0,删除改为当前id', -> front_source varchar(64) comment '前端路径', -> source_name varchar(64) comment '前端名称', -> url varchar(512) comment '后端url用,隔开,可以匹配*', -> parent_id int comment '上一级id', -> source_level varchar(32) comment '权限等级', -> external_id int comment '扩展外部id', -> primary key(id) -> )engine=InnoDB charset=utf8 row_format=dynamic; Query OK, 0 rows affected (0.03 sec) //给他们加入数据 insert into role_auth(delete_id,role_name,level) values (0,'班主任','lv0'); insert into role_auth(delete_id,role_name,level) values (0,'学生','lv1'); insert into role_auth(delete_id,role_name,level) values (0,'通用','common'); insert into user_auth (delete_id,user_id,user_name,role_id) values (0,'teacher01','王育人',1); insert into user_auth (delete_id,user_id,user_name,role_id) values (0,'student01','根正苗红好青年',2); insert into auth_source (delete_id,front_source,source_name,url,parent_id,source_level) values (0,'course_delete','课程删除','/api/course/*','0','lv0'); insert into auth_source (delete_id,front_source,source_name,url,parent_id,source_level) values (0,'course_query','课程新增','/api/course/add','0','lv1');
创建表的时候注意事项:看表单设计需要注意的是,auth_source通过level等级权限关联的,并不是通过role_id权限关联的,如果是通过角色id关联,那业务效果会不太一样,比如现在是通过lv关联,如果校长和老师权限都是lv1,那么校长和老师都会开通一起开通这个权限。
添加数据时候注意事项:
看我添加数据的顺序,我是先给role_auth添加数据的,因为role_id在给用户表添加的时候需要用到,当然不按这个顺序也是可以的,先给用户表添加数据,之后再把角色的role_id修改进去。
3、代码详解
/** * 权限 * * @author keying * @date 2021/9/29 */ @Configuration public class AuthConfiguration implements WebMvcConfigurer { @Resource private AuthSourceMapper authSourceMapper; @Resource private UserAuthMapper userAuthMapper; @Resource private RoleAuthMapper roleAuthMapper; @Resource private AuthService authService; @Override public void addInterceptors(InterceptorRegistry registry) { InterceptorRegistration interceptorRegistration = registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestUrl = request.getRequestURI(); Boolean flag = authService.getAllUrl(requestUrl); if(flag){ return true; } return false; } }); interceptorRegistration.addPathPatterns("/**"); } } package com.alibaba.first.service.lmpl; import java.util.List; import java.util.stream.Collectors; import javax.annotation.Resource; import com.alibaba.first.mapper.AuthSourceMapper; import com.alibaba.first.mapper.RoleAuthMapper; import com.alibaba.first.mapper.UserAuthMapper; import com.alibaba.first.model.AuthSource; import com.alibaba.first.service.AuthService; import org.springframework.stereotype.Service; /** * 权限 * * @author keying * @date 2021/9/29 */ @Service public class AuthServiceImpl implements AuthService { @Resource private AuthSourceMapper authSourceMapper; @Resource private UserAuthMapper userAuthMapper; @Resource private RoleAuthMapper roleAuthMapper; @Override public boolean getAllUrl(String requestUrl) { List<AuthSource> authSourceList = authSourceMapper.getAllUrl(); List<String> urlStringList = authSourceList.stream().map(AuthSource::getUrl).collect(Collectors.toList()); StringBuffer stringBuffer = new StringBuffer(); for (String string : urlStringList) { stringBuffer.append(string); } String urlString = stringBuffer.toString(); //是否包含 if (requestUrl.contains("?")) { //包含问号 requestUrl = requestUrl.substring(0, requestUrl.lastIndexOf("?")); } else { //不包含问号 requestUrl = requestUrl.substring(0, requestUrl.lastIndexOf("/") + 1); } if (urlString.contains(requestUrl)) { //包含,有权限 return true; } else { //不包含 int a = requestUrl.indexOf("/"); int b = requestUrl.indexOf("/", a + 1); int c = requestUrl.indexOf("/", b + 1); requestUrl = requestUrl.substring(0, c); requestUrl = requestUrl + "/*"; if (urlString.contains(requestUrl)) { return true; } return false; } } public static void main(String[] args) { String url1 = "api/course/1"; String url2 = "api/course?pagesize=1&counrentPage=100"; String url3 = "api/course/getById/getByid"; int a = url3.indexOf("/"); int b = url3.indexOf("/", a + 1); String z = url3.substring(0, b); System.out.println(z); } } /** * 权限管理 * * @author keying * @date 2021/9/29 */ @Controller @RequestMapping("/api/course") public class AuthController { /*@DeleteMapping("/id") public void delete(@PathVariable Integer id) { System.out.println("删除" + id); } @PostMapping("/id") public void add(@PathVariable Integer id) { System.out.println("新增" + id); }*/ @RequestMapping("/query") public void query() { System.out.println("查询"); } }