【问题标题】:How to access the "id_token" and "refresh_token" when using spring-security-oauth2 client with OpenID Connect provider?使用带有 OpenID Connect 提供程序的 spring-security-oauth2 客户端时如何访问“id_token”和“refresh_token”?
【发布时间】:2017-08-17 15:21:43
【问题描述】:

我已成功将 Spring Security OAuth2 与我的 Open ID Connect 提供程序 (Forgerock OpenAM) 集成。我可以看到正在检索访问令牌。如何访问id_tokenrefresh_token,它们是来自/token 端点的响应的一部分?

【问题讨论】:

    标签: java spring spring-security spring-security-oauth2 openid-connect


    【解决方案1】:

    终于找到答案并发布,以防它对遇到同样问题的人有用。会话通过 Spring Security OAuth2 认证后,有一个 Authentication 对象设置。它需要转换为OAuth2Authentication 的实例。该对象具有令牌。

        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth instanceof OAuth2Authentication) {
            Object details = auth.getDetails();
            OAuth2AccessToken token = oauth2Ctx.getAccessToken();
    
            if (token != null && !token.isExpired()) {
                // Do Stuff
            }
    

    【讨论】:

      【解决方案2】:

      替代方法的完整示例(使用 Spring Boot 并禁用部分自动配置)。

      application.properties:

      security.oauth2.client.client-id=client-id
      security.oauth2.client.client-secret=client-secret
      security.oauth2.client.access-token-uri=http://my-oidc-provider/auth/oauth2/token
      security.oauth2.client.user-authorization-uri=http://my-oidc-provider/auth/oauth2/authorize
      security.oauth2.resource.token-info-uri=http://my-oidc-provider/auth/oauth2/check_token
      security.oauth2.client.scope=openid,email,profile
      security.oauth2.resource.jwk.key-set-uri=http://my-oidc-provider/auth/oidc/jwks
      
      /**
       * Extending the AuthorizationServerEndpointsConfiguration disables the Spring
       * Boot ResourceServerTokenServicesConfiguration.
       */
      @Configuration
      @EnableOAuth2Sso
      public class OAuth2Config extends AuthorizationServerEndpointsConfiguration {
      
          @Value("${security.oauth2.resource.jwk.key-set-uri}")
          private String keySetUri;
      
          @Value("${security.oauth2.resource.token-info-uri}")
          private String checkTokenEndpointUrl;
      
          @Value("${security.oauth2.client.client-id}")
          private String clientId;
      
          @Value("${security.oauth2.client.client-secret}")
          private String clientSecret;
      
          @Bean
          public RemoteTokenServices resourceServerTokenServices() {
              RemoteTokenServices tokenService = new RemoteTokenServices();
      
              DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
              accessTokenConverter.setUserTokenConverter(new CustomIdTokenConverter(keySetUri));
              tokenService.setAccessTokenConverter(accessTokenConverter);
      
              tokenService.setCheckTokenEndpointUrl(checkTokenEndpointUrl);
              tokenService.setClientId(clientId);
              tokenService.setClientSecret(clientSecret);
      
              return tokenService;
          }
      
          @Bean
          public ClientDetailsService clientDetailsService() {
              return new InMemoryClientDetailsService();
          }
      
          @Bean
          public UserInfoRestTemplateFactory userInfoRestTemplateFactory(
                  ObjectProvider<List<UserInfoRestTemplateCustomizer>> customizers,
                  ObjectProvider<OAuth2ProtectedResourceDetails> details,
                  ObjectProvider<OAuth2ClientContext> oauth2ClientContext) {
              return new DefaultUserInfoRestTemplateFactory(customizers, details,
                      oauth2ClientContext);
          }
      }
      
      public class CustomIdTokenConverter extends DefaultUserAuthenticationConverter {
      
          private final JwkTokenStore jwkTokenStore;
      
          public CustomIdTokenConverter(String keySetUri) {
              this.jwkTokenStore = new JwkTokenStore(keySetUri);
          }
      
          @Override
          public Authentication extractAuthentication(Map<String, ?> map) {
      
              String idToken = (String) map.get("id_token");
      
              OAuth2AccessToken token = jwkTokenStore.readAccessToken(idToken);
      
              Map<String, Object> claims = token.getAdditionalInformation();
              OAuth2RefreshToken refreshToken = token.getRefreshToken();
      
              String principal = (String) claims.get("sub");
      
              List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
      
              return new CustomAuthenticationData(principal, claims, authorities);
          }
      }
      
      public class CustomAuthenticationData extends UsernamePasswordAuthenticationToken {
      
          private final Map<String, Object> attributes;
      
          public CustomAuthenticationData(String username, Map<String, Object> attributes, Collection<? extends GrantedAuthority> authorities) {
              super(username, "N/A", authorities);
              this.attributes = attributes;
          }
      
          public Map<String, Object> getAttributes() {
              return attributes;
          }
      }
      

      【讨论】:

      • 似乎这对于使用由 JWK 签名的 JWT 令牌非常具体。这也适用于不透明的令牌吗?
      • 访问令牌和刷新令牌可能是不透明的令牌,但 OpenID Connect 将 id_token 定义为 JWT,这就是使用 JwkTokenStore 类对其进行解析的原因。
      猜你喜欢
      • 2016-08-26
      • 2012-10-22
      • 2020-04-06
      • 1970-01-01
      • 2016-04-18
      • 2020-02-11
      • 2019-10-15
      • 2023-04-06
      • 2013-06-20
      相关资源
      最近更新 更多