1.拦截器配置
代码如下(示例):
/**
* mvc拦截器
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 如http://localhost:8080/attendance/monthly/submit
// 匹配的路径就是/attendance/monthly/submit
// 配置前缀不算到路径中 server.servlet.context-path=/web
// - /**: 匹配所有路径
// - /attendance/**:匹配 /attendance/ 下的所有路径
// - /attendance/*:只匹配 /attendance/monthly,不匹配 /attendance/monthly/submit
// 添加拦截器,所有路径都拦截
registry.addInterceptor(tokenInterceptor()).addPathPatterns("/**");
}
@Bean
public TokenInterceptor tokenInterceptor() {
return new TokenInterceptor();
}
/*@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
}*/
/*但是使用此方法配置之后再使用自定义拦截器时跨域相关配置就会失效。
原因是请求经过的先后顺序问题,当请求到来时会先进入拦截器中,而不是进入Mapping映射中,所以返回的头信息中并没有配置的跨域信息。浏览器就会报跨域异常。
正确的解决跨域问题的方法时使用CorsFilter过滤器。代码如下:*/
private CorsConfiguration corsConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
/* 请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等)
*/
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setMaxAge(3600L);
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfig());
return new CorsFilter(source);
}
2. 拦截器
代码如下(示例):
public class TokenInterceptor extends HandlerInterceptorAdapter {
// 在方法执行前校验token
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 下面两个判断是基于注解,判断接口上是否配置了自定义注解,只有添加了自定义注解才校验token
// 因为拦截器只想在需要token信息的接口做校验,所以做了这个判断,如果所有token都想校验就不需要配置
if(!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod)handler;
CheckToken apiSecret = handlerMethod.getMethodAnnotation(CheckToken .class);
if (Objects.isNull(apiSecret)) {
return true;
}
// 校验token
String header = request.getHeader("Authorization");
if(StringUtils.isEmpty(header)) {
return false;
};
String token;
String[] headers = header.split("Bearer ");
if (headers == null || headers.length < 2) {
return false;
} else {
token= headers[1];
}
// 通过token获取自定义信息
Claims claims = jwtTokenUtil.getToken(token);
// 获取存入redis中的token
Object object = redisTemplate.opsForValue().get(claims.get("userId").toString());
// token过期或不存在,两次token不一致都返回false
if (null == object && !StringUtils.equals(accessToken, object.toString)) {
return false;
}
return true;
}
}
3. 自定义注解
代码如下(示例):
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckToken {
}