一、前言
在我们写项目时,一个项目通常会有拥有不同角色的用户,在进入某个方法前,会判断该用户是否具有此权限,今天我们来用自定义注解实现一下这个功能。
注解参数不懂的小伙伴可以移步这篇文章:java自定义注解_crazyK.的博客-CSDN博客
二、业务场景
1.场景介绍
假如有一个学生管理系统,我们来对一个用户是否具有对学生管理这个模块操作的权限进行验证
2.数据库
存储用户基本信息的用户表
角色表
用户角色关联表
3.前情提示
在写权限验证之前要把登录功能并传入token,在token里保存登录用户的角色id (后面会用到)
//登录
@RequestMapping("login")
public ResultJson login(User user) {
if (user.getUserName() == null || user.getUserPassword() == null) {
return ResultJson.error("用户名或密码错误!");
}
User userDb = loginService.login(user);
if (userDb == null) {
return ResultJson.error("用户名或者密码错误!");
}
Long uid = userDb.getId();
//查询登录用户具有的角色id
List<Long> roleIdList = loginService.userRoleIdList(uid);
user.setId(uid);
user.setRoleIdList(roleIdList);
//这里设置token
String token = TokenUtil.genToken(user);
User user1 = new User();
user1.setId(userDb.getId());
user1.setUserName(userDb.getUserName());
user1.setUserMail(userDb.getUserMail());
user1.setUserPhone(userDb.getUserPhone());
user1.setToken(token);
user1.setRoleIdList(roleIdList);
user1.setId(userDb.getId());
return ResultJson.ok(GlobalConstant.RESULT_OK_MSG, user1);
}
三、编码
1.创建一个自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
/**
* 权限验证自定义注解
*/
public @interface RoleAuthorize {
String[] value() default {};
}
2.创建一个拦截器
这个拦截器拦截所有访问路径的url,如果访问方法上带有我们创建的自定义注解RoleAuthoeize,则获取这个注解上限定访问的角色,方法中没有注解在获取这个类是否有这个注解,如果都没有,则这个类没有访问权限限制,放行
@Component
public class RoleInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod)handler;
//在方法上寻找注解(这里是反射)
RoleAuthorize permission = handlerMethod.getMethodAnnotation(RoleAuthorize.class);
if (permission == null) {
//方法不存在则在类上寻找注解则在类上寻找注解
permission = handlerMethod.getBeanType().getAnnotation(RoleAuthorize.class);
}
//如果没有添加权限注解则直接跳过允许访问
if (permission == null) {
return true;
}
//获取角色id(登录时用户拥有的角色id存储在了token中)
String token = request.getHeader(GlobalConstant.HEADER_TOKEN);
Long roleId = TokenUtil.getRoleId(token);
String roleId2 = String.valueOf(roleId);
//获取注解中的值
String[] validateRoles = permission.value();
for(int i = 1; i < validateRoles.length; i++){
if (validateRoles[i].equals(roleId2 )){
return true;
}
}
throw new AccessDeniedException("您没有权限!");
}
}
3.注册拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private RoleInterceptor roleInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(roleInterceptor).addPathPatterns("/**");
}
}
四、测试
1.先写几个简单的方法将自定义注解修饰在方法上(修饰在类上也可以)
//增加
//value中的值表示只有拥有角色id为1的管理员或id为2的老师才具有对学生信息操作的权限
@RoleAuthorize(value = {"1","2"})
@RequestMapping("insert")
public ResultJson insert(@RequestBody User user) {
if (studentService.save(user)) {
studentService.insertUserRole(user.getId());
return ResultJson.ok(GlobalConstant.RESULT_OK_MSG, user);
} else {
return ResultJson.error(GlobalConstant.RESULT_ERROR_MSG);
}
}
//修改
@RoleAuthorize(value = {"1","2"})
@RequestMapping("update")
public ResultJson updateById(@RequestBody User user) {
if (studentService.updateById(user)) {
return ResultJson.ok(GlobalConstant.RESULT_OK_MSG, user);
} else {
return ResultJson.error(GlobalConstant.RESULT_ERROR_MSG);
}
}
//删除
@RoleAuthorize(value = {"1","2"})
@RequestMapping("delete")
public ResultJson deleteById(Long id) {
if (studentService.removeById(id)) {
studentService.deleteUserRole(id);
return ResultJson.ok(GlobalConstant.RESULT_OK_MSG, id);
} else {
return ResultJson.error(GlobalConstant.RESULT_ERROR_MSG);
}
}
2.测试
1)先登录
2.调用学生模块的任意一个接口测试
别忘了传入token(要验证用户拥有的角色id)
调用接口
再登录一个只有学生角色的用户
没有权限