簡體   English   中英

Spring 安全性,啟用 Oauth2 時出現 cors 錯誤

[英]Spring security, cors error when enable Oauth2

查詢 oauth/token 端點時出現錯誤。

我已經為我的資源配置了 cors enable / 也嘗試允許所有資源,但沒有任何效果。

XMLHttpRequest 無法加載http://localhost:8080/oauth/token 對預檢請求的響應未通過訪問控制檢查:請求的資源上不存在“Access-Control-Allow-Origin”標頭。 因此,不允許訪問源 ' http://localhost:1111 '。 響應的 HTTP 狀態代碼為 401。

vendor.js:1837 ERROR SyntaxError: Unexpected token u in JSON at position 0
    at JSON.parse (<anonymous>)
    at CatchSubscriber.selector (app.js:7000)
    at CatchSubscriber.error (vendor.js:36672)
    at MapSubscriber.Subscriber._error (vendor.js:282)
    at MapSubscriber.Subscriber.error (vendor.js:256)
    at XMLHttpRequest.onError (vendor.js:25571)
    at ZoneDelegate.invokeTask (polyfills.js:15307)
    at Object.onInvokeTask (vendor.js:4893)
    at ZoneDelegate.invokeTask (polyfills.js:15306)
    at Zone.runTask (polyfills.js:15074)
defaultErrorLogger @ vendor.js:1837
ErrorHandler.handleError @ vendor.js:1897
next @ vendor.js:5531
schedulerFn @ vendor.js:4604
SafeSubscriber.__tryOrUnsub @ vendor.js:392
SafeSubscriber.next @ vendor.js:339
Subscriber._next @ vendor.js:279
Subscriber.next @ vendor.js:243
Subject.next @ vendor.js:14989
EventEmitter.emit @ vendor.js:4590
NgZone.triggerError @ vendor.js:4962
onHandleError @ vendor.js:4923
ZoneDelegate.handleError @ polyfills.js:15278
Zone.runTask @ polyfills.js:15077
ZoneTask.invoke @ polyfills.js:15369

使用 Postman 一切正常。

我的 cors 安全配置:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*")
                .allowedMethods("*")
                .allowCredentials(true);
    }
}

還嘗試在允許的來源中添加http://localhost:1111

郵遞員中的代碼:

require 'uri'
require 'net/http'

url = URI("http://localhost:8080/oauth/token")

http = Net::HTTP.new(url.host, url.port)

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request["authorization"] = 'Basic Y2hhdHRpbzpzZWNyZXRzZWNyZXQ='
request["cache-control"] = 'no-cache'
request["postman-token"] = 'daf213da-e231-a074-02dc-795a149a3bb2'
request.body = "grant_type=password&username=yevhen%40gmail.com&password=qwerty"

response = http.request(request)
puts response.read_body

經過很多努力,我已經覆蓋了類WebSecurityConfigurerAdapter 的方法configure(WebSecurity web)因為授權服務器自己配置它,我只是還沒有找到另一個解決方案。 您還需要 permitAll "/oauth/token" Http.Options 方法。 我的方法:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.OPTIONS, "/oauth/token");
}

在此之后,我們需要添加 cors 過濾器以將 Http 狀態設置為 OK。 我們現在可以攔截 Http.Options 方法。

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter("/*")
public class CorsFilter implements Filter {

    public CorsFilter() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        final HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
        response.setHeader("Access-Control-Max-Age", "3600");
        if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
    }
}

我找到了一種方法來修復 Spring Security 5 和 Spring Security OAuth 2.3.5 上的 401 錯誤,而無需關閉令牌端點上所有OPTIONS請求的安全性。 我意識到您可以通過AuthorizationServerSecurityConfigurer向令牌端點添加安全過濾器。 我嘗試添加一個CorsFilter並且它起作用了。 我對這種方法的唯一問題是我無法利用 Spring MVC 的CorsRegistry 如果有人能弄清楚如何使用 CorsRegistry,請告訴我。

我在下面為我的解決方案復制了一個示例配置:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
@EnableAuthorizationServer
public static class AuthServerConfiguration extends AuthorizationServerConfigurerAdapter {
    //... other config

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        //... other config

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.applyPermitDefaultValues();

        // Maybe there's a way to use config from AuthorizationServerEndpointsConfigurer endpoints?
        source.registerCorsConfiguration("/oauth/token", config);
        CorsFilter filter = new CorsFilter(source);
        security.addTokenEndpointAuthenticationFilter(filter);
    }
}

這對我有用

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception 
      {
        security.tokenKeyAccess("permitAll()")
        .checkTokenAccess("isAuthenticated()");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.applyPermitDefaultValues();

        // add allow-origin to the headers
        config.addAllowedHeader("access-control-allow-origin");

        source.registerCorsConfiguration("/oauth/token", config);
        CorsFilter filter = new CorsFilter(source);
        security.addTokenEndpointAuthenticationFilter(filter);

    }

}

您可以擴展AuthorizationServerSecurityConfiguration並覆蓋void configure(HttpSecurity http)方法以實現自定義cors配置,同時保持其余部分不變。

下面是一個例子:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerSecurityConfiguration;
import org.springframework.web.cors.CorsConfiguration;

public class MyAuthorizationServerSecurityConfiguration extends AuthorizationServerSecurityConfiguration {

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

        http.cors(httpSecurityCorsConfigurer -> httpSecurityCorsConfigurer.configurationSource(request -> {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.addAllowedMethod("POST");
            configuration.addAllowedHeader("Content-Type");

            return configuration;
        }));
    }
}

然后,您可以自己導入相關類,而不是使用@EnableAuthorizationServer默認配置類的默認注解@EnableAuthorizationServer

@Import({AuthorizationServerEndpointsConfiguration.class, MyAuthorizationServerSecurityConfiguration.class})

無需更改與OPTIONS方法和/或特定 oauth 路徑相關的任何安全配置。

我使用 XMLHttpRequest 發送 POST /logout 請求(Keycloak 和 Spring Cloud OidcClientInitiatedServerLogoutSuccessHandler)時出現 CORS 錯誤,所以我改用 HTML 表單:

 <form action="/logout" method="post">
    <button>Logout</button>
 </form>

它可以正常工作,並且不需要 CORS 配置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM