随笔 - 4  文章 - 0  评论 - 3  阅读 - 519

基于自定义注解的简单方法权限管理

基于自定义注解的简单方法权限管理

技术概述

通过拦截器和自定义注解实现权限管理

技术详述

通过为方法加上注解的方式决定什么什么方法是需要token才能使用的,什么方法是不需要token才能使用了,即区分了什么接口是登录后才能使用的,什么接口时不需要登录才能使用的。原理是为方法加上注解,然后在拦截器中拦截所有请求,判断请求的方法加上了什么注解,再进行后续处理。并且具有后续的拓展性,能够通过添加自定义注解的方式创建新的角色,来提供无需修改代码的权限管理。

//编写两个自定义注解 一个用于标记不需要token验证的方法 一个用于标注需要token验证的方法
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    boolean required() default true;
}

添加拦截器配置

public class InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    AuthenticationInterceptor authenticationInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor)//包含权限验证逻辑的拦截器
                .addPathPatterns("/**");//拦截所有请求
    }
}

只实现了prehandle方法,其他两个方法放空 有需要再实现。

流程图:

首先先检测请求是不是映射到方法

       if(!(object instanceof HandlerMethod)){
            return true;//不是映射到某个方法就直接通过该请求
        }

然后获取方法对象并且检查注解的种类

HandlerMethod handlerMethod=(HandlerMethod)object;
Method method=handlerMethod.getMethod();

//检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
    PassToken passToken = method.getAnnotation(PassToken.class);
    if (passToken.required()) {
        return true;
    }
}

如果是需要token的场合则需要验证token

token是否存在

    if (userLoginToken.required()) {
        // 检查是否有token
        if (token == null) {
            throw new CustomException(401,"无token,请重新登录");
        }

token中包含的用户id在数据库中是否存在

// 获取 token 中的 user id
long userId=-1;
try
{
    userId= TokenUtils.getIdInToken(token);
    User user = userService.getUserById(userId);
}
    catch (JWTDecodeException e) {
    e.printStackTrace();
    throw new CustomException(401,"token未通过验证,请重新登录");
}

//检查用户是否存在
User user=userService.getUserById(userId);
if (user == null) {
    throw new CustomException(401,"用户不存在,请重新登录");
}

验证token正确性

//验证token正确性
try {
    TokenUtils.checkToken(token,user.getUserPassword());
} catch (JWTVerificationException e) {
    e.printStackTrace();
    throw new CustomException(401,"toeken失效,请重新登录");
}

通过三重验证基本能确定token有效可用,就能通过该请求。

使用时仅仅需要在方法上加上注解就可以使用,实际方便。

@UserLoginToken
@PostMapping("/Project/Join/{ProjectId}")
public CommonResponse joinProject(@PathVariable long ProjectId, HttpSession httpSession)
{
    projectService.joinProject(httpSession,ProjectId);
    return  new CommonResponse(200,"成功加入项目","");
}

问题和解决过程

1.没有把jwt的解密和加密过程打包成工具类,导致重复代码很多而且很麻烦。

解决:将jwt打包成工具类进行复用也很方便。

2.一开始将token验证设置的太过严格,甚至还设置了token过期时间,前端反馈体验不好。

解决:删除精简了部分逻辑

总结

方便了队友也方便了自己,队友在实现的时候完全不用考虑权限验证的逻辑,做到了模块的分离。

留出了拓展的空间,以应对需求的变化。

参考

  1. [SpringBoot集成JWT实现token验证](https://www.cnblogs.com/shihaiming/p/9565835.html)
posted @ 2021-06-26 01:54  aaagx  阅读(308)  评论(2编辑  收藏  举报