jwt - 使用 Google 进行身份验证时,从 Spring OAuth2 授权服务器发出 JWT token

标签 jwt google-oauth spring-oauth2

我想使用 Spring Oauth 创建一个授权服务器,它能够发布自己的 JWT token 。授权服务器必须将身份验证委托(delegate)给 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

我是如何理解的:看起来当谷歌发布访问 token 时,授权服务器(作为谷歌 OAuth 的客户端)试图将访问 token 解码为 JWT,并抛出异常,因为谷歌的 token 不是有效的 JWT(它只是一个访问 token )。

我想创建一个包含访问 token (将用于访问 Google API)和一些关于用户的附加信息的 JWT。我还希望能够在访问 token 过期时刷新 JWT token 。有什么办法可以实现吗?

最佳答案

我不确定 GMail,但对于您自己的授权服务器,您可以添加一个 token 增强器 JwtAccessTokenConverter,它将您的 token 转换为 JWT。

sample 请引用oauth2-spring-boot-mongo-jwt-sample

通常,正常的 token 负载是以下类型

{
    "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"
}

关于jwt - 使用 Google 进行身份验证时,从 Spring OAuth2 授权服务器发出 JWT token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42694911/

相关文章:

javascript - 欢迎回来,您已经以 * 身份通过 Google+ 登录连接到此应用程序

flask - 带有 Flask-Dance 的 Google OAuth(总是重定向到 "choose account"谷歌页面)

spring-boot - Outh2.0 access_tokens 会被泄露吗?

spring - 如何将 OAuth2 session 存储到数据库中并在 Spring Boot 服务器之间共享

asp.net-mvc - 将 OAuth 不记名 token (JWT) 与 MVC 结合使用

jwt - 如何在 nestjs 中设置更多 "jwt"AuthGuard?

python - 无需每次身份验证即可使用 Google Api 的任何方法?

oauth-2.0 - spring boot OAuth2 基于角色的授权

node.js - 如何在node.js后端和Angular 2前端中使用jwt实现社交登录

.net - 使用 ui-router 版本 1.x 在状态转换中滑动过期的 AngularJS token 身份验证