向 Google 进行身份验证时,从 Spring OAuth2 授权服务器发出 JWT 令牌
Posted
技术标签:
【中文标题】向 Google 进行身份验证时,从 Spring OAuth2 授权服务器发出 JWT 令牌【英文标题】:Issue JWT tokens from Spring OAuth2 Authorization Server when authenticating with Google 【发布时间】:2017-07-30 09:54:14 【问题描述】:我想使用 Spring Oauth 创建一个授权服务器,它能够发布它自己的 JWT 令牌。授权服务器必须将身份验证委托给 Google。我一直在关注本教程,它几乎可以满足我的所有需求:https://spring.io/guides/tutorials/spring-boot-oauth2/
我能够将 Google 添加为身份验证提供程序,但我在 JWT 部分遇到了困难。
这是我的授权服务器配置:
@SpringBootApplication
@EnableOAuth2Client
@EnableAuthorizationServer
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class MsAuthorizationGmailApplication extends WebSecurityConfigurerAdapter
@Autowired
OAuth2ClientContext oauth2ClientContext;
@Override
protected void configure(HttpSecurity http) throws Exception
http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**").permitAll().anyRequest()
.authenticated().and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login/gmail")).and().logout()
.logoutSuccessUrl("/").permitAll().and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
@Bean
@ConfigurationProperties("gmail")
public ClientResources gmail()
return new ClientResources();
private Filter ssoFilter()
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(gmail(), "/login/gmail"));
filter.setFilters(filters);
return filter;
private Filter ssoFilter(ClientResources client, String path)
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
path);
OAuth2RestTemplate template = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
filter.setRestTemplate(template);
filter.setTokenServices(JwtConfig.tokenServices());
return filter;
public static void main(String[] args)
SpringApplication.run(MsAuthorizationGmailApplication.class, args);
在 JWT 配置中,我不想做任何花哨的事情,只是想暂时让它通过:
public final class JwtConfig
private static final String KEY = "123";
private JwtConfig()
private static JwtAccessTokenConverter accessTokenConverter()
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(KEY);
return converter;
private static TokenStore tokenStore()
return new JwtTokenStore(accessTokenConverter());
public static DefaultTokenServices tokenServices()
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
我得到以下异常:
org.springframework.security.authentication.BadCredentialsException: Could not obtain user details from token
at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:122) ~[spring-security-oauth2-2.0.12.RELEASE.jar:na]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:112) [spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:73) [spring-web-4.3.6.RELEASE.jar:4.3.6.RELEASE]
....
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
Caused by: org.springframework.security.oauth2.common.exceptions.InvalidTokenException: Cannot convert access token to JSON
at org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter.decode(JwtAccessTokenConverter.java:287) ~[spring-security-oauth2-2.0.12.RELEASE.jar:na]
at org.springframework.security.oauth2.provider.token.store.JwtTokenStore.convertAccessToken(JwtTokenStore.java:88) ~[spring-security-oauth2-2.0.12.RELEASE.jar:na]
at org.springframework.security.oauth2.provider.token.store.JwtTokenStore.readAccessToken(JwtTokenStore.java:80) ~[spring-security-oauth2-2.0.12.RELEASE.jar:na]
at org.springframework.security.oauth2.provider.token.DefaultTokenServices.loadAuthentication(DefaultTokenServices.java:229) ~[spring-security-oauth2-2.0.12.RELEASE.jar:na]
at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:112) ~[spring-security-oauth2-2.0.12.RELEASE.jar:na]
... 62 common frames omitted
Caused by: java.lang.IllegalArgumentException: JWT must have 3 tokens
at org.springframework.security.jwt.JwtHelper.decode(JwtHelper.java:49) ~[spring-security-jwt-1.0.0.RELEASE.jar:na]
at org.springframework.security.jwt.JwtHelper.decodeAndVerify(JwtHelper.java:74) ~[spring-security-jwt-1.0.0.RELEASE.jar:na]
at org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter.decode(JwtAccessTokenConverter.java:277) ~[spring-security-oauth2-2.0.12.RELEASE.jar:na]
... 66 common frames omitted
我对此的理解:看起来当 Google 发出访问令牌时,授权服务器(作为 Google OAuth 的客户端)尝试将访问令牌解码为 JWT,并抛出异常,因为 Google 的令牌不是有效的 JWT(它只是一个访问令牌)。
我想创建一个 JWT,其中包含访问令牌(将用于访问 Google API)和一些有关用户的其他信息。我还希望能够在访问令牌过期时刷新 JWT 令牌。有什么方法可以实现吗?
【问题讨论】:
【参考方案1】:我不确定GMail,但对于您自己的授权服务器,您可以添加一个令牌增强器JwtAccessTokenConverter
,它将您的令牌转换为JWT。
样品请参考oauth2-spring-boot-mongo-jwt-sample
一般情况下,普通令牌有效负载属于以下类型
"access_token": "bc9c021f-b5ae-43af-9746-737b533f9bc5",
"token_type": "bearer",
"refresh_token": "fee7a2a1-eff9-4757-8dd3-5392ee225bea",
"expires_in": 43199,
"scope": "read-foo"
而 JWT 看起来像这样
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZm9vIl0sInVzZXJfbmFtZSI6InVzZXIiLCJzY29wZSI6WyJyZWFkLWZvbyJdLCJleHAiOjE1MTQ3ODMwNTIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiJlMjM4MDg1YS0xZjFjLTQ5ZWQtODNiMC1iN2Q1MjI5OWUwZjYiLCJjbGllbnRfaWQiOiJ3ZWItY2xpZW50In0.-OSw1Vr4o1dnAQL3n7QFGG6UOXr4itc0Kp8dugyT4zU",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiZm9vIl0sInVzZXJfbmFtZSI6InVzZXIiLCJzY29wZSI6WyJyZWFkLWZvbyJdLCJhdGkiOiJlMjM4MDg1YS0xZjFjLTQ5ZWQtODNiMC1iN2Q1MjI5OWUwZjYiLCJleHAiOjE1MTczMzE4NTIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiIzYTA2OTZmMy1mYzg1LTQ2YTEtYjVlMC01NmQ2OGVmYTJhMmUiLCJjbGllbnRfaWQiOiJ3ZWItY2xpZW50In0.jSBriPfM-rSgHHLyifIuBHwrwCkyb5I2u2AKa8kQUUU",
"expires_in": 43199,
"scope": "read-foo",
"jti": "e238085a-1f1c-49ed-83b0-b7d52299e0f6"
【讨论】:
以上是关于向 Google 进行身份验证时,从 Spring OAuth2 授权服务器发出 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章
使用 google firebase 和 spring 进行身份验证
Spring Boot OAuth2 - 使用本地用户数据库向 Facebook 进行身份验证
使用 Spring Boot OAuth2 针对 Google 进行身份验证时如何将 google 用户电子邮件发送到白名单用户
如何使用 spring security 和 spring boot 对 Google 用户进行身份验证,将 mongoDB 作为存储库?