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"); }