簡體   English   中英

當我在授權 header 中發送我的有效承載令牌時,為什么我的 Spring-Cloud Gateway / OAuth2-Client 沒有通過身份驗證?

[英]Why am I not getting authenticated by my Spring-Cloud Gateway / OAuth2-Client when I am sending my valid bearer-token in the authorization header?

我正在開發一個微服務基礎設施,並開始實施 Spring 雲網關來代理我的所有請求。 我通過spring-boot-starter-oauth2-client Dependency 使用 keycloak 保護了我的網關。 我使用 TokenRelay 過濾器將承載者 append 用於我的代理請求。 我基本上遵循了這個博客https://blog.jdriven.com/2019/11/spring-cloud-gateway-with-openid-connect-and-token-relay/

spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8090/auth/realms/testrealm
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
spring.security.oauth2.client.registration.keycloak.client-id=yyy
spring.security.oauth2.client.registration.keycloak.client-secret=xxx
spring.cloud.gateway.default-filters[0]=TokenRelay

現在我正在將任何匹配 /ping 的請求路由到我的 Ping 微服務。

spring.cloud.gateway.routes[0].id=some-id
spring.cloud.gateway.routes[0].uri=http://localhost:8079
spring.cloud.gateway.routes[0].predicates[0]=Path=/ping

Ping 微服務是一個spring-boot-starter-oauth2-resource-server ,並且配置為這樣,並且只公開一個測試端點 /ping。

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8090/auth/realms/testrealm

@Configuration
@EnableWebSecurity
@RestController
public class SecurityConfig extends KeyCloakSecurityConfig {
    @GetMapping("/ping")
    public String ping() {
        return "hello";
    }
    // ... resource server configuration in KeyCloakSecurityConfig
}

現在我通過 http://localhost:8765/ping 訪問我的網關(在 8765 上運行),我被正確重定向到 keycloak 的登錄頁面。 我使用我的 testuser 登錄,並被重定向到我的網關,然后它將我的請求代理到 Ping 微服務。 PingMicroService 再次針對 Keycloak 驗證 AccessToken,我收到“你好”。

但是,如果我想用例如 Postman 測試我的 API,我會假設,我可以在調用我的 /ping 端點之前將承載令牌添加到授權 Header。 因此,我使用 Token-Endpoint http://localhost:8090/auth/realms/testrealm/protocol/openid-connect/token獲取我的 Accesstoken,並將其復制到我的 Gateway-Request 的 Authorization Header 中。 但是發送后,我得到了登錄頁面,而不是請求的資源。 在此處輸入圖像描述

當我在授權 header 中發送有效的不記名令牌時,為什么我沒有通過網關進行身份驗證?

當我直接調用我的資源服務器時,承載令牌被接受。 這是有道理的,因為 api 網關除了將我的訪問令牌中繼到資源服務器之外沒有做任何其他事情,因此他可以進行必要的令牌自省。

經過一番研究,我發現當我通過瀏覽器進行 api 調用時,Spring 實際上向我發送了一個 SESSION 作為 cookie。 當我將此 SESSION 作為 cookie 復制到我在 postman 中的請求中時,一切正常。 是否有一些關於為什么 Spring 使用 SESSION 的文檔,或者這基本上是 Auth-Code 因為我們在這里使用授權碼流?

更新:經過一番研究,我發現我的網關確實已經是無狀態的,所以 sessioncookie 不是來自我的網關,而是來自 oauth2-client 依賴項(請參閱如何使 API 網關無狀態以使用 Oauth2 進行身份驗證/授權過程? )。 所以我用一個簡單的 Spring 引導應用程序重現了我的問題,使用 keycloak 設置 OAuth2login 並暴露一個端點 /ping。 請參閱https://github.com/smotastic/spring-oauth2-client-keycloak如果您使用有效的 Bearer Access-Token 調用 /ping,應用程序會將您重定向到 keycloak 的登錄頁面,不接受令牌,因為它需要一個有效的 SESSION-Cookie

所以對於任何有類似問題的人。 問題出在 spring-boot-starter-oauth2-client 依賴項中。 通過從授權服務器發回 SESSION-Cookie 而不是 Access-Token,這使我的網關成為有狀態的。

不幸的是,我無法使用 Keycloak 提供的官方 Spring-Boot-Adapter( https://www.keycloak.org/docs/latest/securing_apps/#_spring_boot_adapter ),因為這個適配器有一些 web 依賴項,並且作為 spring-- cloud-gateway 是基於 webflux 構建的,keycloak 需要的 web 依賴不能配合使用。

我的解決方案是,不再使用 spring-cloud-gateway ,而是spring-cloud-starter-netflix-zuul gateway 這是建立在 web 上的,而不是 webflux 上,所以我可以通過 keycloak 使用官方的 Spring-Boot-Adapter。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>

Zuul 也發送一個 JSessionId,但仍然接受請求 header 中的 accesstoken(如果設置)作為有效授權。

請注意,Zuul 被置於維護模式( https://cloud.spring.io/spring-cloud-netflix/multi/multi__modules_in_maintenance_mode.ZFC35FDC70D5FC69D269883A8 )。 所以它不會收到任何新功能,建議使用 spring-cloud-gateway 代替。 但是對於我的用例來說,它是不可行的,所以如果 oauth2-client 發布更新,我可能會在將來 go 回到這個網關,我也可以在其中進行無狀態身份驗證。

這是一個示例存儲庫,它使用 zuul-gateway,由使用官方 Spring-Boot-Keycloak-Adapter 的 keycloak 保護

https://github.com/smo-snippets/spring-cloud-microservices/tree/master/api-gateway

暫無
暫無

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

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