本期目录
- 什么是CORS
- SpringBoot 全局配置CORS
- 拦截器处理预检请求
什么是CORS
跨域(CORS)请求:同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指 “协议+域名+端口” 三者相同, 不同源则跨域。
如果还想了解更多,下面这两个文档更加详细的介绍了CORS
CORS 参考链接:https://developer.mozilla.org/zh-CN/docs/Glossary/CORS
关于HTTP请求分类参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
SpringBoot 版本 2.4.8
SpringBoot 全局配置CORS
添加一个 WebMvc 的配置类,在没有过滤器和拦截器的情况下是ok了。
我这里还配置了一个拦截器,HTTP的预检请求会经过拦截器,我就直接在拦截器里面对预检请求进行处理。(如果配置了过滤器可以在过滤器中进行处理,因为过滤器比拦截器更早经过)
package com.pro.config;
import com.pro.interceptor.BaseInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private static final String[] whiteList = {"/admin/login", "/admin/logout"};
@Autowired
BaseInterceptor baseInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(baseInterceptor).excludePathPatterns(whiteList);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
拦截器处理预检请求
直接在拦截器里面对预检请求进行处理,处理方法就是这个方法 responseCors
核心处理逻辑
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (responseCors(response, request)) {
return false;
}
return true;
}
private boolean responseCors(HttpServletResponse response, HttpServletRequest request) {
if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
response.setHeader("Access-control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setStatus(HttpStatus.OK.value());
return true;
}
return false;
}
完整拦截器代码
package com.pro.interceptor;
import com.pro.constant.ErrorConstant;
import com.pro.utils.*;
import com.pro.vo.user.UserInfoVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class BaseInterceptor implements HandlerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseInterceptor.class);
private static final String USER_AGENT = "user-agent";
private final String[] whiteListPrefix = {"/admin/login", "/admin/css", "/admin/js", "/admin/plugins", "/admin/editormd", "/admin/images"};
@Autowired
private RedisUtil redisUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (responseCors(response, request)) {
return false;
}
String uri = request.getRequestURI();
LOGGER.info("UserAgent: {}", request.getHeader(USER_AGENT));
LOGGER.info("用户访问地址: {}, 来源地址: {}", uri, IPKit.getIpAddrByRequest(request));
UserInfoVO user = redisUtil.getLoginUser(request, true);
if (uri.startsWith("/admin") && user == null && verifyUriPrefix(uri)) {
this.responseResult(response);
return false;
}
return true;
}
private boolean verifyUriPrefix(String uri) {
if (uri == null) return false;
for (String prefix : whiteListPrefix) {
if (uri.startsWith(prefix)) {
return false;
}
}
return true;
}
private void responseResult(HttpServletResponse response) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
response.getWriter().println(JsonKit.toJSON(Result.fail(401, ErrorConstant.Auth.NOT_LOGIN)));
}
private boolean responseCors(HttpServletResponse response, HttpServletRequest request) {
if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
response.setHeader("Access-control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setStatus(HttpStatus.OK.value());
return true;
}
return false;
}
}