SpringSecurity中的跨域問(wèn)題處理方案
跨域問(wèn)題是實(shí)際應(yīng)用開(kāi)發(fā)中一個(gè)非常常見(jiàn)的需求,在Spring框架中對(duì)于跨域問(wèn)題的處理方案有好幾種,引入了Spring Security之后,跨域問(wèn)題的處理方案又增加了。
1.什么是CORS
CORS(Cross-Origin Resource Sharing)是由W3C制定的一種跨域資源共享技術(shù)標(biāo)準(zhǔn),其目的就是為了解決前端的跨域請(qǐng)求。在JavaEE開(kāi)發(fā)中,最常見(jiàn)的前端跨域請(qǐng)求解決方案是早起的JSONP,但是JSONP只支持GET請(qǐng)求,這是一個(gè)很大的缺陷,而CORS則支持多種HTTP請(qǐng)求方法,也是目前主流的跨域解決方案。
CORS中新增了一組HTTP請(qǐng)求頭字段,通過(guò)這些字段,服務(wù)器高爐瀏覽器,哪些網(wǎng)站通過(guò)瀏覽器有權(quán)限訪問(wèn)哪些資源。同時(shí)規(guī)定,對(duì)那些可能修改服務(wù)器數(shù)據(jù)的HTTP請(qǐng)求方法(如GET以外的HTTP請(qǐng)求等),瀏覽器必須首先使用OPTIONS方法發(fā)起一個(gè)預(yù)檢請(qǐng)求(prenightst),預(yù)檢請(qǐng)求的目的是查看服務(wù)端是否支持即將發(fā)起的跨域請(qǐng)求,如果服務(wù)端允許,才發(fā)送實(shí)際的HTTP請(qǐng)求。在預(yù)檢請(qǐng)求的返回中,服務(wù)端也可以通知客戶端,是否需要攜帶身份憑證(如Cookies、HTTP認(rèn)證信息等)。
CORS: 同源/同域 = 協(xié)議 + 主機(jī) + 端口
2.簡(jiǎn)單請(qǐng)求
GET請(qǐng)求為例,如果需要發(fā)起一個(gè)跨域請(qǐng)求,則請(qǐng)求頭如下:
Host: localhost:8080 Origin: http://localhost:8081 Referer: http://localhost:8081/index.html
如果五段支持該跨域請(qǐng)求,那么返回的響應(yīng)頭中將包含如下字段:
Access-Control-Allow-Origin: http://localhost:8081
Access-Control-Allow-Origin字段用來(lái)告訴瀏覽器可以訪問(wèn)該資源的域,當(dāng)瀏覽器收到這樣的響應(yīng)頭信息之后,提取出Access-Control-Allow-Origin字段中的值,發(fā)現(xiàn)該值包含當(dāng)前頁(yè)面所在的域,就知道這個(gè)跨域是被允許的,因此就不再對(duì)前端的跨域請(qǐng)求進(jìn)行限制。這屬于簡(jiǎn)單請(qǐng)求,即不需要進(jìn)行預(yù)檢請(qǐng)求的跨域。
3.非簡(jiǎn)單請(qǐng)求
對(duì)于一些非簡(jiǎn)單請(qǐng)求,會(huì)首先發(fā)送一個(gè)預(yù)檢請(qǐng)求。預(yù)檢請(qǐng)求類(lèi)似下面這樣:
OPTIONS /put HTTP/1.1 Host: localhost:8080 Connection: keep-alive Accept: */* Access-Control-Request-Method: PUT Origin: http://localhost:8081 Referer: http://localhost:8081/index.html
請(qǐng)求方法是OPTIONS,請(qǐng)求頭Origin就鈣素服務(wù)端當(dāng)前頁(yè)面所在域,請(qǐng)求頭Access-Control-Request-Methods告訴服務(wù)器端即將發(fā)起的跨域請(qǐng)求所使用的方法。服務(wù)端對(duì)此進(jìn)行判斷,如果允許即將發(fā)起的跨域請(qǐng)求,則會(huì)給出如下響應(yīng):
HTTP/1.1 200 Access-Control-Allow-Origin:http://localhost: 8081 Access-Control-Request-Methods: PUT Access-Control-Max-Age: 3600
Access-Control-Allow-Methods字段表示允許的跨域方法:Access-Control-Max-Age字段表示預(yù)檢請(qǐng)求的有效期,單位為秒,在有效期內(nèi)如果發(fā)起該跨域請(qǐng)求,則不用再次發(fā)起預(yù)檢請(qǐng)求。預(yù)檢請(qǐng)求結(jié)束后,接下來(lái)就會(huì)發(fā)起一個(gè)真正的跨域請(qǐng)求,跨域請(qǐng)求和前面的簡(jiǎn)單請(qǐng)求跨域步驟類(lèi)似。
4.Spring跨域解決方案
4.1.@CrossOrigin
Spring中第一種處理跨域的方式是通過(guò)@CrossOrigin注解來(lái)標(biāo)記支持跨域,該注解可以添加在方法上,也可以添加在Controller上。當(dāng)添加在Controller上時(shí),表示Controller中的所有接口都支持跨域,具體配置如下:
@RestController
public class IndexController {
@GetMapping("/hello")
@CrossOrigin(origins = "http://localhost:8081")
public String hello(){
System.out.println("hello ok");
return "hello ok";
}
}@CrossOrigin注解各屬性含義如下:
- allowCredentials:瀏覽器是否應(yīng)當(dāng)發(fā)送憑證信息,如Cookie。
- allowedHeaders:請(qǐng)求被允許的請(qǐng)求頭字段,*表示所有字段。
- exposedHeaders:哪些響應(yīng)頭可以作為相應(yīng)的一部分暴露出來(lái)。
注意,這里只可以一一列舉,通配符 * 在這里是無(wú)效的。
- maxAge:預(yù)檢請(qǐng)求的有效期,有效期內(nèi)不必再次發(fā)送預(yù)檢請(qǐng)求,默認(rèn)是1800秒
- methods:允許的請(qǐng)求方法,*表示允許的所有方法。
- origins:允許的域,*表示允許所有域。
4.2.addCrossMapping自定義mvc配置
@CrossOrigin注解需要添加在不同的Controller上。所以還有一種全局配置方法,就是通過(guò)重寫(xiě)WebMvcConfigurerComposite#addCorsMappings方法來(lái)實(shí)現(xiàn),具體配置如下:
//自定義mvc配置類(lèi)
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//用來(lái)全局處理跨域
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //處理的請(qǐng)求地址
.allowedMethods("*")
.allowedOrigins("*")
.allowedHeaders("*")
.allowCredentials(false)
.exposedHeaders("")
.maxAge(3600);
}
}4.3.CorsFilter
CorsFilter是Spring Web中提供的一個(gè)處理跨域的過(guò)濾器,開(kāi)發(fā)者也可以通過(guò)該過(guò)濾器處理跨域。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
/**
* @author zhangKaiTao
* @date 2022/7/24 10:30
*/
//自定義mvc配置類(lèi)
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
FilterRegistrationBean<CorsFilter> corsFilter(){
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("*"));
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",corsConfiguration);
registrationBean.setFilter(new CorsFilter(source));
registrationBean.setOrder(-1);
return registrationBean;
}
}5.SpringSecurity跨域解決方案
當(dāng)我們?yōu)轫?xiàng)目添加了Spring Security依賴(lài)后,發(fā)現(xiàn)上面三種跨域方式有的失效了,有的則可以繼續(xù)使用,這是怎么回事?
通過(guò)@CrossOrigin注解或者重寫(xiě)addCorsMappings方法配置跨域,統(tǒng)統(tǒng)失效了,通過(guò)CorsFilter配置的跨域,有沒(méi)有失效則要看過(guò)濾器的優(yōu)先級(jí),如果過(guò)濾器優(yōu)先級(jí)高于SpringSecurity過(guò)濾器,即先于Spring Security過(guò)濾器執(zhí)行,則CorsFilter所配置的跨域處理依然有效;如果過(guò)濾器優(yōu)先級(jí)地域Spring Security過(guò)濾器,則CorsFilyer所配置的跨域處理就會(huì)失效。
以下是Filter、DispatcherServlet以及Interceptor執(zhí)行順序。

由于非簡(jiǎn)單請(qǐng)求都要首先發(fā)送一個(gè)預(yù)檢請(qǐng)求(request),而預(yù)檢請(qǐng)求并不會(huì)攜帶認(rèn)證信息,所以預(yù)檢請(qǐng)求就有被Spring Security攔截的可能。因此通過(guò)@CrossOrigin注解或者重寫(xiě)addCorsMappings方法配置跨域就會(huì)失效。如果使用CorsFilter配置的跨域,只要過(guò)濾器優(yōu)先級(jí)高于SpringSecurity過(guò)濾器就不會(huì)有問(wèn)題,反之同樣會(huì)出現(xiàn)問(wèn)題。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//...
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.cors().configurationSource(corsConfigurationSource())
.and()
.csrf().disable();//開(kāi)啟csrf
}
CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("*"));
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
corsConfiguration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
}到此這篇關(guān)于SpringSecurity中的跨域問(wèn)題處理方案的文章就介紹到這了,更多相關(guān)SpringSecurity跨域內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot集成ElasticSearch實(shí)現(xiàn)搜索引擎的示例
這篇文章主要介紹了Spring Boot集成ElasticSearch實(shí)現(xiàn)搜索引擎的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
Springboot結(jié)合@validated優(yōu)化代碼驗(yàn)證
這篇文章主要介紹了Springboot與@validated注解結(jié)合從而實(shí)現(xiàn)讓你的代碼驗(yàn)證更清爽,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
springboot2.2.2集成dubbo的實(shí)現(xiàn)方法
這篇文章主要介紹了springboot2.2.2集成dubbo的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
springboot實(shí)現(xiàn)啟動(dòng)直接訪問(wèn)項(xiàng)目地址
這篇文章主要介紹了springboot實(shí)現(xiàn)啟動(dòng)直接訪問(wèn)項(xiàng)目地址,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
獲取JPEGImageEncoder和JPEGCode這兩個(gè)類(lèi)的方法
下面小編就為大家?guī)?lái)一篇獲取JPEGImageEncoder和JPEGCode這兩個(gè)類(lèi)的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
Mybatis-Plus查詢中如何排除標(biāo)識(shí)字段
這篇文章主要介紹了Mybatis-Plus查詢中排除標(biāo)識(shí)字段的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
詳解Java中finally和return的執(zhí)行順序
try-catch-finally是一種針對(duì)程序運(yùn)行時(shí)出錯(cuò)的響應(yīng)手段,對(duì)于一些可以預(yù)料到的出錯(cuò)類(lèi)型,在發(fā)生時(shí)對(duì)其進(jìn)行報(bào)告和補(bǔ)救,這篇文章主要介紹了Java中finally和return的執(zhí)行順序,需要的朋友可以參考下2024-01-01
Java 對(duì) Properties 文件的操作詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了Java 對(duì) Properties 文件的操作詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02
jmeter接口測(cè)試教程及接口測(cè)試流程詳解(全網(wǎng)僅有)
Jmeter是由Apache公司開(kāi)發(fā)的一個(gè)純Java的開(kāi)源項(xiàng)目,即可以用于做接口測(cè)試也可以用于做性能測(cè)試。本文給大家分享jmeter接口測(cè)試教程及接口測(cè)試流程,感興趣的朋友跟隨小編一起看看吧2021-12-12

