最近项目,要实现部分指定接口验证token。于是就想到了,自定义注解来实现。看了一下,别人的实现自己也写了一下。但是实际中也遇到了坑,后边摸索半天终于解决了。
1.创建一个自定义注解,这里我只是作用在方法上,就没有加作用在类上。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface TokenVerification { }
2.创建一个拦截器,实现HandlerInterceptor。判断接口上是否有注解,如果有则判断请求是否携带token。未携带,则返回自定义封装的response。若携带token,再
进行下一步操作。
@Component @Slf4j public class TokenVerificationInterceptor implements HandlerInterceptor { private static final String LOGIN_SESSION_KEY = "login_session"; @Autowired private StringRedisTemplate stringRedisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { final HandlerMethod handlerMethod = (HandlerMethod) handler; final Method method = handlerMethod.getMethod(); TokenVerification tokenVerificationByMethod = AnnotationUtils.findAnnotation(method, TokenVerification.class); if (Objects.isNull(tokenVerificationByMethod)) return true; //判断是否存在token String token = request.getHeader("token"); if (token == null) { returnValue(response); } else { String loginSession = stringRedisTemplate.opsForValue().get(token); if (null != loginSession) { request.setAttribute(LOGIN_SESSION_KEY, loginSession); } } } return true; } /** * token不存在设置返回值 * @param response * @throws IOException */ private void returnValue(HttpServletResponse response) throws IOException { ApiResult result = ApiResult.build(ResultCode.BAD_REQUEST + ResultCode.RESOURCE_COMMON + TalentpoolECode.TOKEN_NOT_EXIST, "token不存在"); ObjectMapper mapper = new ObjectMapper(); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(result)); } }
3.将拦截器注册入,springmvc中。
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private TokenVerificationInterceptor tokenVerificationInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenVerificationInterceptor).addPathPatterns("/**"); } }
4.使用方法,只需要在我们需要拦截的接口上 加入自定义注解。则可对此接口进行拦截token校验。
@DeleteMapping("/{id}") @TokenVerification public ApiResult<Boolean> delete(@PathVariable Integer id) { log.info("id update params: {}", JSON.toJSONString(id)); return clueCustomerWorkService.deleteClueWorkExperience(id); }
这里注意在第二步,中 (handler instanceof HandlerMethod) 这个判断,如果这里返回false则。会导致,错误的url被springMVC拦截处理。返回,则所有的错误url本来应该返回为404的url都会返回200.
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
(handler instanceof HandlerMethod)