TokenEnhancer 不仅将附加信息添加到 jwt,还添加到响应对象中

Posted

技术标签:

【中文标题】TokenEnhancer 不仅将附加信息添加到 jwt,还添加到响应对象中【英文标题】:TokenEnhancer adds additional info not only to jwt but into responce object too 【发布时间】:2019-07-01 13:17:24 【问题描述】:

请帮助从响应对象中排除其他信息并仅添加到JWT

我添加tokenEnhancer 以向JWT 添加附加信息,但它也出现在响应对象中。

“ACCESS_TOKEN”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyLXJlc291cmNlIl0sImZ1bGxfbmFtZSI6ImhleWJhdCBndWxpeWV2IiwidXNlcl9uYW1lIjoiaGV5YmF0Iiwic2NvcGUiOlsicmVhZCIsIndyaXRlIiwidHJ1c3QiXSwiZXhwIjoxNTQ5NTQxNTkwLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiY2Y5ZmY0ZDMtOGZiYi00NWFlLWJhMzEtYWM0MjUzNGFjNDI2IiwiY2xpZW50X2lkIjoibXktdHJ1c3RlZC1jbGllbnQifQ.QLVoRxv0kpTx-ruTR55ldMcQzl8M1KGjuWVeNYlH5Ly35vvdA3PvZelYZVpGq0BDr4fHyiUKy-MLP1H0X8_qiT_2onMHTtzvVDa6Wjrx4Ri3q0wOvXQlyFGenz73kxcHkK-YQ8Y8FYKnq3NUBhz-FBFf9JaQOcmsNrrNiF64SlpU3fO2uqbbP6_1_bQ9QHhOHMXxtk0Scz7-gFZm9Ln92K10wd4jLvp1yvSU9X1Hh9lBafB-WAHgVt5eoaZzrbZ7YJYUqNBifoW77NMisNdWIDIqL90jeKBGN6GVm7QRJOo9wNV6tsOLP9-fRgbHu_teqOQe5v_gK3f52xr4jBYs2w” "token_type": "承载者", “refresh_token”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyLXJlc291cmNlIl0sImZ1bGxfbmFtZSI6ImhleWJhdCBndWxpeWV2IiwidXNlcl9uYW1lIjoiaGV5YmF0Iiwic2NvcGUiOlsicmVhZCIsIndyaXRlIiwidHJ1c3QiXSwiYXRpIjoiY2Y5ZmY0ZDMtOGZiYi00NWFlLWJhMzEtYWM0MjUzNGFjNDI2IiwiZXhwIjoxNTQ5NjI3ODEwLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiMjRkYzliNDEtMTdiMC00ZGQ2LWI3ZTgtODljMWNiNWRmMWQ2IiwiY2xpZW50X2lkIjoibXktdHJ1c3RlZC1jbGllbnQifQ.cIi1yfyNt-komhvduQFPAC098jeEeeqHbiU6HFDNk5uNuvR5HwYkjpKkowvRaLfpXTPGHgpmwNSr3I8LolESLzTfjtPRmFsbrRaLavib5_h32-EpJi5RBKbjhtItxGYbku92K5AxSH9dJ8ceRYg3VQi6zSKrodXXekIdrgtPaGvmEuMcEZF7Oh2qekzvo5u8_1ShZptc76dmAWADMrbHgFxggxioBBOGI27YWvnIPFVLV-RMxrh6FjM_Cy7Tr5BF_13klJvlF2EapkgDQMx0KL53cWvzriZOiDhLcJ6jJk2Cm7oMI5qobcHx7sGD5OC49UYn9LSHQzqh6RqRhckI5g” “过期”:179, “范围”:“读写信任”, "full_name": "heybat guliyev", “jti”:“cf9ff4d3-8fbb-45ae-ba31-ac42534ac426”

如您所见,全名也出现在响应对象中

package com.hqsoft.shop.config;

import com.hqsoft.shop.entities.User;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;

import java.util.HashMap;
import java.util.Map;

/****** to add additional info in token structure ******/
public class CustomTokenEnhancer implements TokenEnhancer 
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) 
        User user = (User) authentication.getPrincipal();
        Map<String, Object> map = new HashMap<>();
        map.put("full_name", user.getFullName());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(map);
        System.out.println(accessToken);
        return accessToken;
    


package com.hqsoft.shop.config;

import com.hqsoft.shop.service.ClientService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;

import java.util.Arrays;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter 

    private PasswordEncoder oauthClientPasswordEncoder;
    private AuthenticationManager authenticationManager;
    private ClientService clientService;

    public AuthorizationServer(PasswordEncoder oauthClientPasswordEncoder,
                               AuthenticationManager authenticationManager,
                               ClientService clientService
    ) 
        this.oauthClientPasswordEncoder = oauthClientPasswordEncoder;
        this.authenticationManager = authenticationManager;
        this.clientService = clientService;
    

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) 
        security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").passwordEncoder(oauthClientPasswordEncoder);
    

    /******   for configuring client ******/
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
        clients.withClientDetails(clientService);
    

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) 
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));

        endpoints
                .tokenStore(tokenStore())
                .authenticationManager(authenticationManager)
                .tokenEnhancer(tokenEnhancerChain);
    

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

    @Bean
    @Primary
    public DefaultTokenServices defaultTokenService() 
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    

    @Bean
    public TokenStore tokenStore() 
        return new JwtTokenStore(jwtAccessTokenConverter());
    

    /******   jwt token implementation  ******/
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() 
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("keys.jks");
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, "*******".toCharArray());
        jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("mykey"));
        return jwtAccessTokenConverter;
    

【问题讨论】:

【参考方案1】:

重写DefaultUserAuthenticationConverter的convertUserAuthentication方法:

public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter 
   @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) 
      Map<String, Object> response = super.convertUserAuthentication(authentication);

      // Add additional info
      User user = (User) authentication.getPrincipal();
      response.put("full_name", user.getFullName());
      return response;
   

在您的配置中创建一个新的令牌转换器并将其用户令牌转换器设置为您的新 CustomUserAuthenticationConverter,然后在您的 jwtAccessTokenConverter 中使用此令牌转换器:

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() 
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("keys.jks");
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, "*******".toCharArray());
        jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("mykey"));

        // ...
        AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
        tokenConverter.setUserTokenConverter(new CustomUserAuthenticationConverter());
        jwtAccessTokenConverter.setAccessTokenConverter(customAccessTokenConverter);
        // ...

        return jwtAccessTokenConverter;
    

最后,只使用这个令牌转换器而不是令牌增强器链:

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) 
    endpoints
            .tokenStore(tokenStore())
            .authenticationManager(authenticationManager)
            .tokenConverter(jwtAccessTokenConverter());

【讨论】:

以上是关于TokenEnhancer 不仅将附加信息添加到 jwt,还添加到响应对象中的主要内容,如果未能解决你的问题,请参考以下文章

如何向 Symfony/Monolog 日志输出添加附加信息(主机、URL 等)?

在不删除原始 UserDefault 信息的情况下将数组附加到 UserDefaults

保存按钮未附加到右侧信息窗口,谷歌地图

将用户信息导出到 CSV - 附加列

附加信息:您无法添加或更改记录,因为表 'tblRubriek' 中需要相关记录

使用 Pandas、Python 将数据附加到 HDF5 文件