当我在授权头中发送有效的承载令牌时,为什么我没有得到spring云网关/oauth2客户端的身份验证?

huwehgph  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(301)

我正在开发一个微服务基础设施,并开始实施一个spring云网关来代理我的所有请求。我通过spring-boot-starter-oauth2-client依赖关系用keydrope保护了我的网关。我使用tokenrelay过滤器将承载者附加到我的代理请求中。我基本上是关注这个博客的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
}

现在,我访问我的网关(在8765上运行),通过http://localhost:8765/ping我被正确重定向到keydrope的登录页。我使用testuser登录,并被重定向到网关,然后网关将代理我的请求到ping微服务。pingmicroservice根据keydrope再次验证accesstoken,我收到“hello”。
但是如果我想用postman测试我的api,我会假设,在调用我的/ping端点之前,我可以将承载令牌添加到授权头中。所以我用令牌端点获取accesstokenhttp://localhost:8090/auth/realms/testrealm/protocol/openid connect/token,并将其复制到我的网关请求的授权头中。但是在发送之后,我得到的是登录页面,而不是请求的资源。

当我在授权头中发送有效的承载令牌时,为什么我没有通过我的网关进行身份验证?
当我直接调用我的资源服务器时,承载令牌被接受。这是有意义的,因为api网关除了将我的访问令牌中继到资源服务器之外,没有做任何其他事情,所以他可以进行必要的令牌内省。
经过一番研究,我发现当我通过浏览器进行api调用时,spring实际上会将一个会话作为cookie发送给我。当我将此会话作为cookie复制到postman中的请求时,一切正常。是否有一些文档说明spring为什么使用会话,或者这基本上是身份验证代码,因为我们在这里使用的是授权代码流?
更新:经过一些研究,我发现我的网关确实已经是无状态的,因此sessioncookie不是来自我的网关,而是来自oauth2客户机依赖(请参阅如何使用oauth2使api网关成为无状态的身份验证/授权过程?)。因此,我用一个简单的spring启动应用程序重现了我的问题,用keydrope设置oauth2login并公开一个端点/ping。看到了吗https://github.com/smotastic/spring-oauth2-client-keycloak 如果您使用有效的承载访问令牌调用/ping,应用程序会将您重定向到keyposet的登录页,而不接受令牌,因为它需要有效的会话cookie

vsnjm48y

vsnjm48y1#

所以对于任何有类似问题的人。问题出在spring-boot-starter-oauth2-client依赖关系中。通过从授权服务器发回会话cookie而不是访问令牌,这使我的网关成为有状态的。
不幸的是,我不能使用keydeap提供的官方spring引导适配器(https://www.keycloak.org/docs/latest/securing_apps/#_spring_boot_adapter)因为这个适配器有一些web依赖项,而且SpringCloudGateway是在webflux上构建的,所以Key斗篷所需的web依赖项不能结合使用。
我的解决方案是,不再使用spring云网关,而是使用spring云入门版netflix zuul网关。这是建立在web上的,而不是webflux上的,所以我可以通过keydove使用官方的spring引导适配器。

<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,但仍然接受请求头中的accesstoken(如果已设置)作为有效授权。
注意,zuul处于维护模式(https://cloud.spring.io/spring-cloud-netflix/multi/multi__modules_in_maintenance_mode.html). 因此它不会收到任何新特性,建议改用springcloudgateway。但是对于我的用例来说,这是不可行的,所以如果oauth2客户机发布更新,我将来可能会回到这个网关,在那里我也可以进行无状态身份验证。
下面是一个示例存储库,它使用zuul网关,由使用官方spring boot keydepot适配器的keydepot保护
https://github.com/smo-snippets/spring-cloud-microservices/tree/master/api-gateway

相关问题