網站首頁 編程語言 正文
SpringBoot添加Cors跨域配置,解決No Access-Control-Allow-Origin header is present on the requested resource
作者:weixin_44953227 更新時間: 2022-04-09 編程語言本期目錄
- 什么是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;
/**
* 擴展 Web MVC
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private static final String[] whiteList = {"/admin/login", "/admin/logout"};
@Autowired
BaseInterceptor baseInterceptor;
/**
* 配置攔截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(baseInterceptor).excludePathPatterns(whiteList);
}
/**
* 配置跨域請求
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//設置允許跨域請求的域名
.allowedOriginPatterns("*")
// 設置允許請求方式
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD")
// 是否允許證書(cookies)
.allowCredentials(true)
// 預請求的結果能被緩存多久
.maxAge(3600)
// 設置允許的請求頭
.allowedHeaders("*");
}
}
攔截器處理預檢請求
直接在攔截器里面對預檢請求進行處理,處理方法就是這個方法 responseCors
核心處理邏輯
/**
* 請求方法執行之前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在進入這個攔截器之前,對跨域提供支持
if (responseCors(response, request)) {
return false;
}
return true;
}
/**
* 在進入這個攔截器之前, 對跨域提供支持
* @param response
* @param request
* @return
*/
private boolean responseCors(HttpServletResponse response, HttpServletRequest request) {
// 判斷是否是預檢請求
if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
// response.setHeader("Cache-Control","no-cache");
response.setHeader("Access-control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
response.setHeader("Access-Control-Allow-Headers", "*");
// 跨域時會首先發送一個OPTIONS請求,這里我們給OPTIONS請求直接返回正常狀態
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;
/**
* 請求方法執行之前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@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;
}
/**
* 驗證 uri 是否在白名單中
* @param uri 統一資源標志符/路由
* @return boolean
*/
private boolean verifyUriPrefix(String uri) {
if (uri == null) return false;
for (String prefix : whiteListPrefix) {
// 判斷 uri 是否以白名單的前綴開頭
if (uri.startsWith(prefix)) {
return false;
}
}
return true;
}
/**
* 用戶未登錄 使用 response 返回結果
* @param response
* @throws IOException
*/
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)));
}
/**
* 在進入這個攔截器之前, 對跨域提供支持
* @param response
* @param request
* @return
*/
private boolean responseCors(HttpServletResponse response, HttpServletRequest request) {
if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
// response.setHeader("Cache-Control","no-cache");
response.setHeader("Access-control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
response.setHeader("Access-Control-Allow-Headers", "*");
// 跨域時會首先發送一個OPTIONS請求,這里我們給OPTIONS請求直接返回正常狀態
response.setStatus(HttpStatus.OK.value());
return true;
}
return false;
}
}
原文鏈接:https://blog.csdn.net/weixin_44953227/article/details/119281830
相關推薦
- 2022-07-07 深入理解Go語言實現多態?_Golang
- 2022-12-05 C?sharp?(#)?數據類型獲取方式_C#教程
- 2021-12-19 C/C++?Qt?TabWidget?實現多窗體創建詳解_C 語言
- 2024-02-16 springboot開啟mybatis二級緩存
- 2022-07-21 SpringBoot默認開啟AOP,采用Cglib代理方式?(Spring AOP快速入門)
- 2022-09-02 Redis解決Session共享問題的方法詳解_Redis
- 2023-01-28 C#實現XML文件操作詳解_C#教程
- 2023-06-05 Python?time時間格式化和設置時區實現代碼詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支