前言:今天在寫項目的時候碰到了跨域問題,在網站找了各種解決辦法,大部分都是添加@CrossOrigin注解或者添加配置類,但我花了整整一天還是沒能解決問題。后來實在是不行,便想起了官網文檔。結果還真的找到了解決辦法!!!而且官方文檔中還指明了原因!!看來以后遇到bug先要查查官網。
參考官方文檔:https://docs.spring.io/spring-security/site/docs/5.4.2/reference/html5/#jc
問題描述

原因
Spring Framework provides first class support for CORS. CORS must be processed before Spring Security because the pre-flight request will not contain any cookies (i.e. the
JSESSIONID). If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it.
由上文可知,當使用Spring Security時,一定要在Spring Security認證前解決跨域問題。因為在跨域的場景下,瀏覽器在發送真實請求前會先發送一個預請求(簡單請求不會發送)。預請求的請求方法是OPTIONS,沒有攜帶數據,目的是測試從瀏覽器到服務器通不通。如果請求成功,就證明從瀏覽器到服務器通,那么瀏覽器就會發送真實的請求。


如果服務器沒有在Spring Security之前處理掉預請求,那么在用戶進行登錄操作時,Spring Security就會對預請求進行攔截。因為預請求不攜帶數據(token、session等),因此Spring Security便無法為其進行認證與授權,而是直接拒絕服務。這也就導致用戶無法登錄。
解決
官網里面給出了解決方法,不需要使用@CrossOrigin,只需要簡單的配置就可以,以下是官網給出的配置:
Java配置類:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors(withDefaults())
...
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
或者XML的方式:
<http>
<cors configuration-source-ref="corsSource"/>
...
</http>
<b:bean id="corsSource" class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
...
</b:bean>
我才用的是配置類的方式。官網給出的方法用着有些別扭,我進行了一些調整,但功能相同:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new UnauthorizedEntryPoint())
.and().csrf().disable()
// by default uses a Bean by the name of corsConfigurationSource
.cors(withDefaults())//一定不要忘
.authorizeRequests()
.anyRequest().authenticated()
// 需要自定義配置,退出請求地址
.and().logout().logoutUrl("/examination/user/logout")
.addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()
.addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))
.addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
configuration.setAllowCredentials(true);
configuration.addAllowedOrigin("http://主機:端口號");
configuration.addAllowedHeader(CorsConfiguration.ALL);
configuration.addAllowedMethod(CorsConfiguration.ALL);
source.registerCorsConfiguration("/**", configuration);
return source;
}
配置完重啟項目,大功告成!!!
