Spring Boot自定义注释制作API接口拦截器进行TOKEN验证

一:自定义注解

1
2
3
4
5
6
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ChackToken {
    boolean validate() default true;
}

二:自定义拦截器来实现 HandlerInterceptorAdapter

因为我使用jeecg-boot,使用拦截后发现积木报表设计访问报错, cannot be cast to org.springframework.web.method.HandlerMethod] ,要解决这种方法,配置不会被拦截的链接进行排除

addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例
addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns("/**")对所有请求都拦截
excludePathPatterns:用于设置不需要拦截的过滤规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
public class AuthorizationInterceptor  extends HandlerInterceptorAdapter implements WebMvcConfigurer {
 
    //redis操作各种方法
    @Autowired
    private RedisUtil redisUtil;
    public static final String USER_KEY = "userInfo";
 
    @Autowired
    private MiniWechatController miniWechatC;
 
    @Override
    public void addInterceptors(InterceptorRegistry registry){
         
        // 配置不会被拦截的链接 顺序判断
        registry.addInterceptor(new SignAuthInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/jmreport/**")        //积木报表
                .excludePathPatterns("/**/*.js.map")
                .excludePathPatterns("/**/*.css.map")
                .excludePathPatterns("/**/*.html");
    }
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 判断会被拦截的链接
        if(handler instanceof  HandlerMethod){
            //不是自定义ChackToken注释的跳过拦截
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            ChackToken annotation = handlerMethod.getMethodAnnotation(ChackToken.class);
            System.out.println("annotation+++:"+annotation);
            if(annotation == null || !annotation.validate()){
                return true;
            }
            /**
             * 项目在拦截器Interceptor中 注入RedisUtil,RedisUtil无法使用的问题(RedisUtil报null错误)
             * 原因:拦截器在SpringContext初始化之前就执行了,Bean初始化之前它就执行了,所以它肯定是无法获取SpringIOC容器中的内容的。
             * 需要加入以下代码代码即可
             */
            if (redisUtil == null) {
                WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
                redisUtil = wac.getBean(RedisUtil.class);
            }
 
            //设置跨域--开始
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
                setHeader(httpRequest,httpResponse);
                return true;
            }
            //设置跨域--结束
 
 
            //从header中获取token
            String token = request.getHeader("token");
            //如果header中不存在token,则从参数中获取token
            if(StringUtils.isBlank(token)){
                token = request.getParameter("token");
            }
            //token为空
            if(StringUtils.isBlank(token) || token == null || token.length() == 0){
                throw new RemoteException("缺少token,拒绝访问");
            }
            Object userInfo = redisUtil.get(token);
            if(userInfo == null ){
                throw new RemoteException("用户Token失效,请重新登录");
            }
            JSONObject jsonObject = JSONObject.parseObject(userInfo.toString());
            // TODO JSONObject转实体类
            ChUser user = com.alibaba.fastjson.JSONObject.parseObject(jsonObject.get("userInfo").toString(),ChUser.class);
            //设置openid到request里,后续根据openid,获取用户信息*/
            request.setAttribute(USER_KEY, userInfo);
            return true;
        }
        return true;
    }
 
    /**
     * 为response设置header,实现跨域
     */
    private void setHeader(HttpServletRequest request,HttpServletResponse response){
        //跨域的header设置
        response.setHeader("Access-control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", request.getMethod());
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
        //防止乱码,适用于传输JSON数据
        response.setHeader("Content-Type","application/json;charset=UTF-8");
    }
 
}

  

三:将自己定义的拦截器注入到Mvc中

这里有两种方式:

第一种是可以继承WebMvcConfigurationSupport,但是用这种我遇到一个问题就是,所有date-format格式被转成了时间戳!

第二种就是实现WebMvcConfigurer,这种不会出现这种情况,所以推荐第二种方式,创建WebMvcConfigurer

1
2
3
4
5
6
7
8
@SpringBootConfiguration
public class SpringMvcConfig implements WebMvcConfigurer {
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthorizationInterceptor());
    }
}

  

现在我们就可以在控制器中进行使用了

示例:

1
2
3
4
5
6
@GetMapping("/text")
@ChackToken
public Result<ChUser> updateUser(HttpServletRequest request){
    System.out.print("userInfo:"+request.getAttribute("userInfo"));
    return Result.error("0");
}

  

posted @   智昕  阅读(347)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示