【问题标题】:Spring Secuity 5: Persist and access Oauth2 refresh tokenSpring Security 5:持久化和访问 Oauth2 刷新令牌
【发布时间】:2020-07-04 10:02:04
【问题描述】:

我的 Spring Boot 客户端应用程序如何访问由例如提供的刷新令牌。谷歌在 Spring Security 5 中?

很简单的问题。远程授权服务器(例如 Google)发送一个刷新令牌,我想使用它。在 Spring Security 5 中持久化和检索它的最佳方式是什么?

似乎 this answerthis questionthis exernal link 描述了一种不再兼容的方法,因为 Oauth2 在 Spring Security 5 中成为一等公民。

上下文:

刷新令牌允许客户端应用程序在用户会话过期后继续访问资源。 Per Google's docs,刷新令牌应该是持久的:

应用程序应存储刷新令牌以供将来使用,并使用访问令牌访问 Google API。

Spring 安全性使 访问令牌OAuth2AuthenticationToken 的形式广泛使用,但其中不包含刷新令牌。

刷新令牌在OidcUserService(或覆盖它的类)中也不可用,因为public OidcUser loadUser(OidcUserRequest userRequest) 无权访问刷新令牌。这很糟糕,因为使用自定义类覆盖 OidcUserService 会很好,该类可以从 OIDC 用户详细信息中创建/检索用户并同时保存其关联的刷新令牌

OAuth2LoginAuthenticationFilter 将刷新令牌保存在 ClientRegistrationRepository 中:

OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
    authenticationResult.getClientRegistration(),
    oauth2Authentication.getName(),
    authenticationResult.getAccessToken(),
    authenticationResult.getRefreshToken());

this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, oauth2Authentication, request, response);

默认实现将令牌保存在临时内存中,这不适合分布式应用程序或在重启后持续存在。

似乎有一个JdbcOauth2AuthorizedClientServicedocs recently added 和一个schema that suggests 可能有用,但没有提供配置它或使用它检索刷新令牌的示例。

那么客户端应用程序如何在 Spring Security 5 中持久化和访问刷新令牌?

【问题讨论】:

    标签: spring-security oauth-2.0 spring-security-oauth2 refresh-token


    【解决方案1】:

    JdbcOauth2AuthorizedClientService 确实适合您的用例。配置非常简单。 首先,您需要将此表添加到您的数据库中:

    CREATE TABLE oauth2_authorized_client (
      client_registration_id varchar(100) NOT NULL,
      principal_name varchar(200) NOT NULL,
      access_token_type varchar(100) NOT NULL,
      access_token_value blob NOT NULL,
      access_token_issued_at timestamp NOT NULL,
      access_token_expires_at timestamp NOT NULL,
      access_token_scopes varchar(1000) DEFAULT NULL,
      refresh_token_value blob DEFAULT NULL,
      refresh_token_issued_at timestamp DEFAULT NULL,
      created_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
      PRIMARY KEY (client_registration_id, principal_name)
    );
    

    然后,配置JdbcOauth2AuthorizedClientService bean:

    @Bean
    public OAuth2AuthorizedClientService oAuth2AuthorizedClientService
            (JdbcOperations jdbcOperations, ClientRegistrationRepository clientRegistrationRepository) {
        return new JdbcOAuth2AuthorizedClientService(jdbcOperations, clientRegistrationRepository);
    }
    

    请注意,当前的实现有一个错误,将在几天后到期的 spring-security 版本 5.3.2 中解决。

    【讨论】:

    • 你知道这是否只支持某些数据库吗?我正在尝试将其与 Postgres 12 一起使用,并且遇到将令牌值(字节 [])强制转换为 Types.BLOB 的异常。当使用 Types.BLOB 时,PgPreparedStatement 期望数据类型是 instanceof Blob 或 InputSteam。由于 Postgres 中没有“blob”数据类型,我尝试过使用 OID、BYTEA 和 TEXT,但问题似乎是在 Postgres 中使用带有 byte[] 的 java.sql.Types.BLOB 的冲突(驱动程序 42.2.12)
    • @JoshCollins 它应该支持 SQL DB 的所有标准功能。您应该在github.com/spring-projects/spring-security/issues 上打开一个问题
    • @StavShamir 如果我目前在我的项目中只使用 Spring JPA,我应该仍然使用 JdbcOauth2AuthorizedClientService 还是使用 JPA 编写自己的服务?
    • @Andreas 如果你可以使用JdbcOauth2AuthorizedClientService,但你也可以使用 JPA 编写自己的。如果您不需要自定义行为,我认为最好使用提供的服务。
    • 从 Spring Security 5.4.1(截至 2020 年 10 月的最新版本)开始,JdbcOauth2AuthorizedClientService 不适用于 Postgres(除非您进行额外配置)。我正在努力解决这个问题,请参阅github.com/spring-projects/spring-security/pull/9070
    猜你喜欢
    • 2013-09-13
    • 2020-04-19
    • 2017-04-14
    • 2019-03-03
    • 2020-02-10
    • 2017-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多