springboot自定义注解拦截请求指定路径的指定方法上有某个注解就必须带token
1.先来自定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
}
其中注解@Retention可以用来修饰注解,是注解的注解,称为元注解。
按生命周期来划分可分为3类:
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。
那怎么来选择合适的注解生命周期呢?
首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。
2,来一个拦截器类
@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
@Autowired
private TokenService tokenService;
public static final String USER_KEY = "userId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//设置跨域--开始
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
setHeader(httpRequest,httpResponse);
return true;
}
//设置跨域--结束
Login annotation;
if(handler instanceof HandlerMethod) {
annotation = ((HandlerMethod) handler).getMethodAnnotation(Login.class);
}else{
return true;
}
if(annotation == null){
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)){
throw new RenException(ErrorCode.TOKEN_NOT_EMPTY);
}
//查询token信息
TokenEntity tokenEntity = tokenService.getByToken(token);
if(tokenEntity == null || tokenEntity.getExpireDate().getTime() < System.currentTimeMillis()){
throw new RenException(ErrorCode.TOKEN_INVALID);
}
//设置userId到request里,后续根据userId,获取用户信息
request.setAttribute(USER_KEY, tokenEntity.getUserId());
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");
}
}
上面有些是数据库的操作, preHandle:在方法被调用前执行。在该方法中可以做类似校验的功能。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行。
3.写一个请求拦截类,让拦截器生效
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthorizationInterceptor authorizationInterceptor;
@Autowired
private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor).addPathPatterns("/api/**");
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(loginUserHandlerMethodArgumentResolver);
}
}
这里拦截了所有请求前面有/api的请求
至此自定义注解拦截操作已经做完,在有/api/ * * 的请求,只要加上@Login注解都需要tonken验证,不然就会抛出异常