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


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

    技术概述

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

    技术详述

    通过为方法加上注解的方式决定什么什么方法是需要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)
  • 相关阅读:
    听豆瓣架构变迁分享会总结
    业界对生成图片缩略图的做法归纳
    58和百姓网的技术学习
    减少存储过程封装业务逻辑-web开发与传统软件开发的思维模式不同
    网站速度问题排查与定位经验
    调度思想-现实中的事物与技术里面其实存在类似道理
    关于图片或者文件在数据库的存储方式归纳
    mysql单表体积和一个库设计多少张表为妥
    php的变量引用与销毁机制
    选择技术方案权衡时,考虑对其可控性很重要
  • 原文地址:https://www.cnblogs.com/aaagx/p/14933237.html
Copyright © 2020-2023  润新知