带有 JWT 的 Spring OAuth2 - 分离身份验证和资源服务器时无法将访问令牌转换为 JSON [英] Spring OAuth2 with JWT - Cannot convert access token to JSON When Separating Auth and Resource Servers

查看:24
本文介绍了带有 JWT 的 Spring OAuth2 - 分离身份验证和资源服务器时无法将访问令牌转换为 JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望使用 Spring Boot 创建一个可以被多个资源服务器使用的 OAuth2 身份验证服务器.因此,我需要将两台服务器创建为独立的应用程序.我的主要参考资料是

如果您在 application.properties 中有以下所有条目,请交叉检查

我怀疑您可能错过了 application.properties 中的一些配置条目

此后,当我使用 JWT 令牌访问资源服务器时,它返回正确的响应

一个说明:同样在这个例子中,他们使用对称密钥来加密 JWT 令牌.因此,即使在资源服务器中,在accessTokenConverter方法中,也应该使用setSigningKey.当使用非对称密钥进行加密时,将使用setVerifierKey

我看到您发布了关于同一主题的另一个问题.你的理解是正确的.JWT 令牌可以被多个资源服务器使用.

I am looking to use Spring Boot to create an OAuth2 Authentication server that could be used by multiple Resource server. Consequently, I am needing to create the two servers as independent apps. My primary references have been this article and this Stack Overflow question.

The referenced article combines both server types into a single app. I am having difficulty separating them.

I am able to retrieve a token using the following:

curl testjwtclientid:XY7kmzoNzl100@localhost:8080/oauth/token -d grant_type=password -d username=john.doe -d password=jwtpass

This call returns:

{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdGp3dHJlc291cmNlaWQiXSwidXNlcl9uYW1lIjoiam9obi5kb2UiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTE1MDUzOTMxLCJhdXRob3JpdGllcyI6WyJTVEFOREFSRF
9VU0VSIl0sImp0aSI6IjBhY2ZlOTA5LTI1Y2MtNGFmZS1iMjk5LTI3MmExNDRiNzFhZCIsImNsaWVudF9pZCI6InRlc3Rqd3RjbGllbnRpZCJ9.ctWt8uNR55HS2PH0OihcVnXuPuw_Z33_zk6wE1qx_5U","token_type":"bearer","expires_in":43199,"scope":"read w
rite","jti":"0acfe909-25cc-4afe-b299-272a144b71ad"}

However, whenever I attempt to use the token to contact my resource server, I receive an error:

    curl localhost:8090/springjwt/test -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdGp3dHJlc291cmNlaWQiXSwidXNlcl9uYW1lIjoiam9obi5kb2UiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNTE1MDUzOTMxLCJhdXRob3JpdGllcyI6WyJTVEFOREFSRF9VU0VSIl0sImp0aSI6IjBhY2ZlOTA5LTI1Y2MtNGFmZS1iMjk5LTI3MmExNDRiNzFhZCIsImNsaWVudF9pZCI6InRlc3Rqd3RjbGllbnRpZCJ9.ctWt8uNR55HS2PH0OihcVnXuPuw_Z33_zk6wE1qx_5U"

{"error":"invalid_token","error_description":"Cannot convert access token to JSON"}

Auth Server config (from article):

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Value("${security.jwt.client-id}")
    private String clientId;

    @Value("${security.jwt.client-secret}")
    private String clientSecret;

    @Value("${security.jwt.grant-type}")
    private String grantType;

    @Value("${security.jwt.scope-read}")
    private String scopeRead;

    @Value("${security.jwt.scope-write}")
    private String scopeWrite = "write";

    @Value("${security.jwt.resource-ids}")
    private String resourceIds;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
        configurer
                .inMemory()
                .withClient(clientId)
                .secret(clientSecret)
                .authorizedGrantTypes(grantType)
                .scopes(scopeRead, scopeWrite)
                .resourceIds(resourceIds);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        enhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
        endpoints.tokenStore(tokenStore)
                .accessTokenConverter(accessTokenConverter)
                .tokenEnhancer(enhancerChain)
                .authenticationManager(authenticationManager);
    }

}

Auth Server security config:

 @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${security.signing-key}")
    private String signingKey;

    @Value("${security.encoding-strength}")
    private Integer encodingStrength;

    @Value("${security.security-realm}")
    private String securityRealm;

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(new ShaPasswordEncoder(encodingStrength));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .httpBasic()
                .realmName(securityRealm)
                .and()
                .csrf()
                .disable();

    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(signingKey);
        return converter;
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    @Primary //Making this primary to avoid any accidental duplication with another token service instance of the same name
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
}

Resource Server config:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Autowired
    private ResourceServerTokenServices tokenServices;

    @Value("${security.jwt.resource-ids}")
    private String resourceIds;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId(resourceIds).tokenServices(tokenServices);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().and().authorizeRequests().antMatchers("/actuator/**", "/api-docs/**").permitAll()
                .antMatchers("/springjwt/**").authenticated();
    }
}

Resource Server Security config:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${security.signing-key}")
    private String signingKey;

    @Value("${security.encoding-strength}")
    private Integer clientID;

    @Value("${security.security-realm}")
    private String securityRealm;

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(signingKey);
        return converter;
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean ResourceServerTokenServices tokenService() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        OAuth2AuthenticationManager authManager = new OAuth2AuthenticationManager();
        authManager.setTokenServices(tokenService());
        return authManager;
    }

}

The entry point:

    @SpringBootApplication
@EnableResourceServer
public class ResourceApp {

    public static void main(String[] args) {
        SpringApplication.run(ResourceApp.class, args);
    }
}

Thanks for any help.

EDIT:

{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}

If I remove the Bearer portion (per one of the responses here), I receive the following:

解决方案

The issue is, in the Resource Server you should use verifier key instead of signing key.

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setVerifierKey(signingKey);
    return converter;
}

Edit 01/05: Downloaded the source code that you have referred in your post (link) and separated the Resource Server Component into an independent App

Have it cross checked if you have all the below entries in the application.properties

I am suspecting that you might have missed some config entries in the application.properties

After this, when I hit the Resource Server with the JWT token, it returns proper response

One Clarification: Also in this example, they are using symmetric Key for encrypting the JWT token. Hence, even in the Resource Server, in the accessTokenConverter method, setSigningKey should be used.setVerifierKey will be used when an asymmetric key is used for encryption

I saw you had posted another question on the same topic. Your understanding is correct. JWT token can be used by multiple Resource Servers.

这篇关于带有 JWT 的 Spring OAuth2 - 分离身份验证和资源服务器时无法将访问令牌转换为 JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆