在spring boot中设置`security.oauth2.resource.jwk.key-set-uri`时的预期行为是什么

时间:2017-09-28 09:58:46

标签: spring-boot

在spring boot中,配置Resource server后,如果访问令牌为JWT且发行者为客户端提供获取公共RSA密钥的端点,则可以选择设置security.oauth2.resource.jwk.key-set-uri属性。以JWK格式验证。

从此JWK启动密钥库的预期行为是什么?该属性正在加载ResourceServerProperties.JWK,但后来是什么。 spring boot应该调用这个URI并获取jwks然后创建一个商店供我验证吗?

我正在按照本教程设置密钥库http://www.baeldung.com/spring-security-oauth-jwt

的配置
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("public.txt");
        String publicKey = null;
        try {
            publicKey = IOUtils.toString(resource.getInputStream());
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
        converter.setVerifierKey(publicKey);
        return converter;
    }

但我没有加载.pem公钥,而是想从jwk加载它。

2 个答案:

答案 0 :(得分:2)

如果要使用JWKS,请使用JwkTokenStore代替JwtTokenStore

spring-security-oauth2/jwk在内部根据auth0 spec

进行密钥加载和管理

您还可以看到有关自动配置的文档,但是我觉得配置起来非常简单(请参阅下文)。

我们不必进行任何验证,因为JwkTokenStore使用@Value("{jsecurity.oauth2.resource.jwk.key-set-uri}")公开的JWKS通过JwkDefinitionSource JwkVerifyingJwtAccessTokenConverter设置了验证。

但是,Spring的spring-security-oauth2/jwk类没有任何公共构造函数,我们经常需要并且可以在AccessTokenConversion中执行任何自定义步骤,就像通常需要将jwt内容提取到auth上下文中一样,我们可以始终向JwkTokenStore

注入自定义转换器
import org.springframework.security.oauth2.provider.token.store.jwk.*;
import org.springframework.security.oauth2.provider.token.store.*
import org.springframework.security.oauth2.provider.token.*;
import java.utl.*;

@Configuration
class JwtConfiguration {

  @Bean
  public DefaultTokenServices tokenServices(final TokenStore tokenStore) {
    final DefaultTokenServices dts = new DefaultTokenServices();
    dts.setTokenStore(tokenStore);
    dts.setSupportRefreshToken(true);
    return dts;
  }

  @Bean
  public TokenStore tokenStore( 
    @Value("{jsecurity.oauth2.resource.jwk.key-set-uri}") final String jwksUrl,
    final JwtAccessTokenConverter jwtAccessTokenConverter) {
    return new  JwkTokenStore(jwksUrl, jwtAccessTokenConverter, null);
  }

  @Bean
  public JwtAccessTokenConverter createJwtAccessTokenConverter() {
    final JwtAccessTokenConverter converter;   
    converter.setAccessTokenConverter(new  DefaultAccessTokenConverter() {
      @Override
      public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
        final OAuth2Authentication auth = super.extractAuthentication(map);
        auth.setDetails(map); //this will get spring to copy JWT content into 
        return auth;
        }

      }
    return conveter;
  }

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
@Configuration
@EnableResourceServer
class ResourceServerConfig extends ResourceServerConfigurerAdapter {

  private String resourceId;
  private TokenStore tokenStore;

  public ResourceServerConfig(
    @Value("\${jwt.reourceId}") private String resourceId,
    private TokenStore tokenStore) {
           this.resourceId = resourceId;
           this.tokenStore = tokenStore;
  }

  /**
  * Ensures request to all endpoints ore a
  @Override 
  public void configure(final HttpSecurity http) {
    http.csrf().disable()
     .authorizeRequests()
     .antMatchers("/**").authenticated();
  }

  /**
  * Configure resources
  * Spring OAuth expects "aud" claim in JWT token. That claim's value should match to the resourceId value
  * (if not specified it defaults to "oauth2-resource").
  */
   @Override 
   public void configure(final ResourceServerSecurityConfigurer resources) {
     resources.resourceId(resourceId).tokenStore(tokenStore);
   }
}

答案 1 :(得分:0)

此实现的主要目标是使用相应的JWK(JSON WEB TOKEN KEY SET)在本地验证JWT。用于验证的JWK使用JWT的kid header参数和JWK的kid属性进行匹配。

服务器可以在本地验证此令牌,而无需发出任何网络请求,与数据库通信等。这可能会使会话管理更快,因为您无需在每次请求时从数据库(或缓存)加载用户,只需要运行一小部分本地代码。这可能是人们喜欢使用JWT的最大原因:它们是无国籍的。