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

一:自定义注解

@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:用于设置不需要拦截的过滤规则

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

@SpringBootConfiguration
public class SpringMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthorizationInterceptor());
    }
}

  

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

示例:

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

  

posted @ 2023-02-09 15:56  智昕  阅读(324)  评论(0编辑  收藏  举报