【问题标题】:What is the expected behavior when setting `security.oauth2.resource.jwk.key-set-uri` in spring boot在 Spring Boot 中设置 `security.oauth2.resource.jwk.key-set-uri` 时的预期行为是什么
【发布时间】:2018-03-10 00:41:01
【问题描述】:

在 Spring Boot 中,配置 Resource server 后,如果访问令牌将是 JWT,我们可以选择设置 security.oauth2.resource.jwk.key-set-uri 属性,并且颁发者为客户端提供端点以获取公共 RSA 密钥以进行 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 加载它。

【问题讨论】:

    标签: spring-boot


    【解决方案1】:

    如果您想使用 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);
       }
    }
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 2019-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-15
        • 2021-11-09
        • 1970-01-01
        • 1970-01-01
        • 2021-07-03
        相关资源
        最近更新 更多