Spring Security-对OPTIONS调用的403状态响应 [英] Spring security - 403 status response on OPTIONS call

查看:199
本文介绍了Spring Security-对OPTIONS调用的403状态响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的后端托管在Heroku上,前端托管在Netlify上.当我在后端调用端点时,它将发送预检选项,但它的状态为403.我确实在寻找解决方案,但仍然无法正常工作.

I have backend hosted on Heroku, and frontend on Netlify. When I call endpoint on backend it sends preflight OPTIONS but it gives 403 status. I did search for solution but it still not working.

我希望能够使用主体为从FE到BE的"POST" 方法调用"/authenticate" 端点.

I want to be able to call "/authenticate" endpoint with "POST" method with body from FE to BE.

Spring安全性配置(仅是配置方法)

Spring security configuration (just configuration methods)

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    ...

    @Override
    public void configure(WebSecurity web) throws Exception
    {
        web.ignoring()
                .antMatchers(HttpMethod.POST, "/authenticate", "/register")
                .antMatchers(HttpMethod.GET, "/token")
                .antMatchers("/h2-console/**")
                .antMatchers("/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {

        http
                .cors()
                .and()
                .csrf().disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/authenticate").permitAll()
                .antMatchers(HttpMethod.GET, "/user-data").authenticated()
                .anyRequest().authenticated()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(List.of(<MY-URL>));
        configuration.setAllowedHeaders(List.of("*"));
        configuration.setMaxAge(Long.valueOf(3600));
        configuration.setAllowedMethods(Arrays.asList("GET","POST", "OPTIONS"));
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    }
}

然后从FE拨打电话

var req = new XMLHttpRequest();
    req.open('POST', API_URL + '/authenticate', true);
    req.setRequestHeader("Content-Type", "application/json");
    req.withCredentials = true;
    req.onreadystatechange = function (aEvt) {
        if (req.readyState === 4) {
            if(req.status === 200) {
                console.log(req.responseText);
                isAuthenticationSucessful = true;
            }
            else
                console.log("Error loading site");
        }
    };

    req.send(JSON.stringify({username, password}));

浏览器开发工具:

Reason: CORS header 'Access-Control-Allow-Origin' missing
Reason: CORS request did not succeed

推荐答案

TL; DR

请确保在 setAllowedOrigins("https://myrul.com")中没有斜杠,或者您的浏览器发送的原点完全相同.

Make sure that in setAllowedOrigins("https://myrul.com") you don't have trailing slash or you have exactly the same origin that your browser send.

如果您的端点位于 web.ignoring(... 中,请从此处删除它,然后将其放入(与我的示例端点一起) http.authorizeRequests().antMatchers("/authenticate).permitAll()

If your endpoint is in web.ignoring(... delete it from here and put it in (with my example endpoint) http.authorizeRequests().antMatchers("/authenticate").permitAll()

(根据我所讨论的代码,是 web http )

(web and http according to my code in question)

更长

所以我在评论中怎么说,使它无法正常工作的一件事是在 corsConfigurationSource 中设置 setAllowedOrigins("https://myrul.com/").请注意,后跟斜杠.

So how I said in my comment, one thing that make it not working correctly was setting setAllowedOrigins("https://myrul.com/") in corsConfigurationSource. Notice that trailing slash.

但是我注意到在开发工具中,浏览器发送的原始标头是这样的: Origin:https://myrul.com 而不用斜杠结尾.为了使其正常工作,我必须将允许的原点更改为正确的原点,例如: setAllowedOrigins("https://myrul.com")(不带斜杠).这使浏览器能够向服务器发送请求,并获得200个响应,但是浏览器不接受来自服务器cuz CORS的响应.

But I noticed in dev-tools that browser send origin header like this: Origin: https://myrul.com without trailing slash. To make it works I have to change allowed origins to proper origin like this: setAllowedOrigins("https://myrul.com") (without trailing slash). This make browser able to send requests to server, and get 200 response, but browser don't accept response from server cuz CORS.

接下来的事情是,我将端点设置在 web.ignoring("/authenticate")... 中,并根据此问题春季安全配置-HttpSecurity与WebSecurity 该语句可防止Spring Security Filter Chain出现在标头 Access-Control-Allow-Origin 的位置,该标头告诉浏览器它可以接受响应. MDN Access-Control-Allow-Origin

The next thing was that I have my endpoint in web.ignoring("/authenticate")... and according to this question Spring Security Configuration - HttpSecurity vs WebSecurity this statement prevents Spring Security Filter Chain where it should header Access-Control-Allow-Origin which tell browser that it can accept response. MDN Access-Control-Allow-Origin

因此,答案是将我的端点从 web.ignoring("/authenticate")转到 http.authorizeRequests().antMatchers("/authenticate").permitAll().

So the answer for that was take my endpoint from web.ignoring("/authenticate") to http.authorizeRequests().antMatchers("/authenticate").permitAll().

但这会带来另一个问题,那就是现在要去过滤器链和我的自定义过滤器 http.addFilterBefore(new JwtFilter()... ),因此请确保采用自定义过滤器您的需要.

But this makes another problem, that is it will go now to filter chain and to my custom filter http.addFilterBefore(new JwtFilter()..., so make sure to adopt custom filters to yours need.

这篇关于Spring Security-对OPTIONS调用的403状态响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆