Spring Security下解决跨域问题


前言:今天在写项目的时候碰到了跨域问题,在网站找了各种解决办法,大部分都是添加@CrossOrigin注解或者添加配置类,但我花了整整一天还是没能解决问题。后来实在是不行,便想起了官网文档。结果还真的找到了解决办法!!!而且官方文档中还指明了原因!!看来以后遇到bug先要查查官网。

参考官方文档:https://docs.spring.io/spring-security/site/docs/5.4.2/reference/html5/#jc

问题描述

image-20210210225641737

原因

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,没有携带数据,目的是测试从浏览器到服务器通不通。如果请求成功,就证明从浏览器到服务器通,那么浏览器就会发送真实的请求。

image-20210210225957566

image-20210210230037728

如果服务器没有在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;
    }

配置完重启项目,大功告成!!!


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM