Spring JWT - 添加自定义声明

Posted

技术标签:

【中文标题】Spring JWT - 添加自定义声明【英文标题】:Spring JWT - Add custom claims 【发布时间】:2018-07-05 23:24:42 【问题描述】:

你能帮我解决我的问题吗?我使用 Spring OAuth2 为我的客户生成了 JWT。我已经实现了一个授权和资源服务器以及一些网络安全配置,一切都通过在线指南完成。

它工作正常,但现在我想编辑有效负载并添加自定义属性,例如用户的名字和姓氏等。你能检查我的代码并告诉我应该怎么做才能将其他属性添加到有效负载中吗?谢谢。

这是我的实现:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig 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 BCryptPasswordEncoder());
    

    @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;
    

授权服务器:

@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;

    @Value("$security.jwt.expiration")
    private int expiration;

    @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)
                .accessTokenValiditySeconds(expiration);
    

    @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);
    

资源服务器:

@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();
    

【问题讨论】:

实现AuthenticationProvider怎么样? 【参考方案1】:

我必须添加 iat(发布于)声明。我实现了一个自定义令牌增强器 CustomTokenEnhancer。

    public class CustomTokenEnhancer implements TokenEnhancer 
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) 

           Map<String, Object> info = new HashMap<>();
           info.put("iat", Instant.now().getEpochSecond());
           ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);

           return accessToken;
        

    

然后使用 setTokenEnhancers() 注册增强器。请记住将 tokenEnhancer() 添加为 链中的第一个

     @Bean
     public TokenEnhancer tokenEnhancer() 
        return new CustomTokenEnhancer();
     

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();

        enhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter));
        endpoints.tokenStore(tokenStore)
                .accessTokenConverter(accessTokenConverter)
                .tokenEnhancer(enhancerChain)
                .authenticationManager(authenticationManager).tokenGranter(tokenGranter(endpoints));
    

【讨论】:

使用.tokenEnhancer(enhancerChain)时不需要.accessTokenConverter(accessTokenConverter)。仅当未指定 tokenEnhancer 时才会使用 accessTokenConverter

以上是关于Spring JWT - 添加自定义声明的主要内容,如果未能解决你的问题,请参考以下文章

向 ID 令牌 OpenID 添加自定义声明

JWT 如何添加自定义声明和解码声明

ASP.NET Core 2.1 Jwt 设置自定义声明

无法在 Tymon JWT 中添加自定义声明

如何使用 JJWT 从有效负载中获取自定义字段

如何根据用户输入在 Jwt Token 上添加自定义声明?