使用带有 OpenID Connect 提供程序的 spring-security-oauth2 客户端时如何访问“id_token”和“refresh_token”?
Posted
技术标签:
【中文标题】使用带有 OpenID Connect 提供程序的 spring-security-oauth2 客户端时如何访问“id_token”和“refresh_token”?【英文标题】:How to access the "id_token" and "refresh_token" when using spring-security-oauth2 client with OpenID Connect provider? 【发布时间】:2017-08-17 15:21:43 【问题描述】:我已成功将 Spring Security OAuth2 与我的 Open ID Connect 提供程序 (Forgerock OpenAM) 集成。我可以看到正在检索访问令牌。如何访问id_token
和refresh_token
,它们是来自/token
端点的响应的一部分?
【问题讨论】:
【参考方案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
类对其进行解析的原因。以上是关于使用带有 OpenID Connect 提供程序的 spring-security-oauth2 客户端时如何访问“id_token”和“refresh_token”?的主要内容,如果未能解决你的问题,请参考以下文章
现在他们正在弃用他们的 OpenID2 提供程序,因此与 Google 进行 OpenID Connect 委托?