When allowCredentials is true, allowedOrigins cannot contain the
special value "*"since that cannot be set on the
“Access-Control-Allow-Origin” response header. To allow credentials to
a set of origins, list them explicitly or consider using
“allowedOriginPatterns” instead.
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private LoginInterceptor loginInterceptor;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowCredentials(true)
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.
// 添加拦截器
addInterceptor(loginInterceptor).
// 添加拦截路径
addPathPatterns("/**").
// 白名单
excludePathPatterns("/login");
}
}
123456789101112131415161718192021222324252627
登录拦截器
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Resource
private RedisTemplate<Object, Object> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("拦截器===>" + "LoginInterceptor.preHandle");
// PreFlight请求,忽略本拦截器
// 浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request)
// 从而获知服务端是否允许该跨源请求
// 服务器确认允许之后,才发起实际的 HTTP 请求
// 如果是预检请求 没有做登录验证直接放行
// 没有放心 在下面的操作中不能从请求头中取得token
if (CorsUtils.isPreFlightRequest(request)) {
return true;
}
//...登录验证的操作
}
}
123456789101112131415161718192021222324
在跨域请求中, 会有一次预检请求.
跨源资源共享 (CORS) (或通俗地译为跨域资源共享)是一种基于HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。
如, 再一次登录的过程中,
首先会发送一次 OPTIONS 请求, 请求头如下:
OPTIONS /manager/login HTTP/1.1
Host: 192.168.161.31:8083
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://192.168.161.31:8080
Sec-Fetch-Mode: cors
Referer: http://192.168.161.31:8080/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
1234567891011
服务端支持CROS之后, 给出的部分响应头如下
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: GET,HEAD,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Origin: http://192.168.161.31:8080
Access-Control-Max-Age: 3600
Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Connection: keep-alive
Content-Length: 0
Date: Thu, 14 Jan 2021 12:04:29 GMT
Keep-Alive: timeout=60
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
12345678910111213
注意响应头中有一个 Access-Control-Allow-Origin 字段, 用来记录可以访问该资源的域, 当浏览器收到这样的响应头信息之后, 就会提取该字段的值, 发现该字段的值包含当前页面所在的域, 就知道这次的跨域是可以被允许的, 因此就不在对前端的跨域请求进行限制.
在跨域的整个过程中, 不需要对前端的代码进行修改, 主要是后端进行处理.
欢迎批评指正
敬礼!
参考资源:
SpringBoot升级2.4.0所出现的问题:When allowCredentials is true, allowedOrigins cannot contain the specia
CORS详解
SpringBoot + Vue全栈开发实战