SpringBoot+Spring Security無法實現跨域的解決方案
SpringBoot+Spring Security無法實現跨域
未使用Security時跨域:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.*; @Configuration @AutoConfigureBefore(SecurityConfig.class) public class MyMvcConfigurer implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry registry){ LOGGER.info("跨域已設置"); registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }
整合Security時發現隻用上述方法前後端分離時仍存在跨域問題,
解決方法如下:
@Configuration @AutoConfigureBefore(Swagger2Configuration.class) @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) @Order(-1) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginProcessingUrl("/user/login") .loginPage("/singIn.html") .successHandler(moyuAuthenticationSuccessHandler) .failureHandler(moyuAuthenticationFailureHandler) .and() .apply(moyuSocialSecurityConfig) .and() .rememberMe() .tokenRepository(persistentTokenRepository()) .tokenValiditySeconds(3600*24*7) .userDetailsService(userDetailsService) .and() .authorizeRequests() .antMatchers("/user/login","/login","/singIn.html","**","/**").permitAll() .anyRequest() .authenticated() .and() .cors() .and() .csrf().disable(); } }
重點加入代碼:
.and() .cors()//新加入 .and() .csrf().disable();
引用Spring Security 項目的跨域處理
最近項目采用瞭前後端分離的框架,前端和後臺接口沒有部署到一個站點,出現瞭跨域問題,什麼是跨域,這裡就不再贅述,直接說解決辦法。
Spring 解決跨域的方式有很多,個人采用瞭Crosfilter的方式
具體代碼如下:
@Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); final CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); return new CorsFilter(urlBasedCorsConfigurationSource); }
配置完成後,測試調用,報錯401,依然不行。網上查資料得知,跨域請求會進行兩次。具體流程見下圖:
每次跨域請求,真正請求到達後端之前,瀏覽器都會先發起一個preflight request,請求方式為OPTIONS 詢問服務端是否接受該跨域請求,具體參數如下圖:
但是該請求不能攜帶cookie和自己定義的header。
由於項目中引入瞭Spring security ,而我使用的token傳遞方式是在header中使用authorization 字段,這樣依賴Spring Security攔截到 preflight request 發現它沒有攜帶token,就會報錯401,沒有授權。
解決這個問題很簡單,可以使用以下配置
讓Spring security 不校驗preflight request 。
@Override public void configure(HttpSecurity http) throws Exception { ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests(); registry.requestMatchers(CorsUtils::isPreFlightRequest).permitAll();//讓Spring security放行所有preflight request }
再試就搞定瞭,但是後端直接配置支持跨域會導致兩次請求。還使用另一種方式,使用Nginx 轉發一下請求也可以。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 關於springboot2.4跨域配置問題
- 教你用Java SpringBoot如何解決跨域
- 解決SpringBoot自定義攔截器和跨域配置沖突的問題
- 最新springboot解決跨域的幾種方式小結
- springboot 設置CorsFilter跨域不生效的解決