05.怎么拓展token?

拓展token其实就是让生成token的map信息更多

但是目前调用细节我还不清楚

  1. 生成token(DefaultTokenServices类),然后调用tokenEnhancer链进行增强,jwt令牌的加强就是在这里做的
	private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
        //可以看源码,token的value就是简单的uuid
		DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
		int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
		if (validitySeconds > 0) {
			token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
		}
		token.setRefreshToken(refreshToken);
		token.setScope(authentication.getOAuth2Request().getScope());

        
		return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
	}

  1. 从上一段代码的最后一行进入(accessTokenEnhancer.enhance(token, authentication)),JwtAccessTokenConverter.java中
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
		DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
		Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());
		String tokenId = result.getValue();
		if (!info.containsKey(TOKEN_ID)) {
			info.put(TOKEN_ID, tokenId);
		}
		else {
			tokenId = (String) info.get(TOKEN_ID);
		}
    	//将扩展的信息放入
		result.setAdditionalInformation(info);
    	//通过这里生成jwt令牌并替换原来的uuid value
		result.setValue(encode(result, authentication));
		
    	...
		return result;
	}
  1. 从上一段代码的倒数第二句进入到调用链底层,DefaultAccessTokenConverter.java中,根据原有的token与authentication转化为生成token(这里是jwt)的原料map
public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
		Map<String, Object> response = new HashMap<String, Object>();
		OAuth2Request clientToken = authentication.getOAuth2Request();

		...
		
         //生成jwt令牌时放入扩展信息
		response.putAll(token.getAdditionalInformation());

		...
		return response;
	}
  1. 从上上段代码的倒数第二句进入,利用上一段代码的结果,根据map生成jwt令牌,JwtAccessTokenConverter.java中
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
    String content;
    try {
       content = objectMapper.formatMap(tokenConverter.convertAccessToken(accessToken, authentication));
    }
    catch (Exception e) {
       throw new IllegalStateException("Cannot convert access token to JSON", e);
    }
    String token = JwtHelper.encode(content, signer).getEncoded();
    return token;
}

从这里我们可以知道,在DefaultAccessTokenConverter.java中会将额外信息放入map中,response.putAll(token.getAdditionalInformation());,所以想要扩展jwt令牌的话,就要在生成jwt令牌前,将额外信息添加到token的的AdditionalInformation中,也就是 setAdditionalInformation

例子:

@Slf4j
@Component("MyTokenEnhancer")
public class MyTokenEnhancer implements TokenEnhancer {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        Map<String,Object> additionalInfo = new HashMap<>();
        Object principal = authentication.getPrincipal();
        try {
            String s = objectMapper.writeValueAsString(principal);
            log.info("{}",s);
            Map map = objectMapper.readValue(s, Map.class);
            map.remove("password");
            map.remove("authorities");
            map.remove("accountNonExpired");
            map.remove("accountNonLocked");
            map.remove("credentialsNonExpired");
            map.remove("enabled");
            additionalInfo.put("user_info",map);
            //这一句话,放入AdditionalInformation中
            ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(additionalInfo);
        } catch (IOException e) {
            log.error("",e);
        }
        return accessToken;
    }
}
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
    @Bean(name="authorizationServerTokenServicesCustom")
        public AuthorizationServerTokenServices tokenService() {
            DefaultTokenServices service=new DefaultTokenServices();
            service.setSupportRefreshToken(true);//支持刷新令牌
            service.setTokenStore(tokenStore);//令牌存储策略

            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
            //这一句话,完成了在生成jwt令牌前添加信息
            //配置扩展信息,一定要将自定义的TokenEnhancer放在前面,否则无效
            tokenEnhancerChain.setTokenEnhancers(Arrays.asList(myTokenEnhancer,accessTokenConverter));
            service.setTokenEnhancer(tokenEnhancerChain);

            service.setClientDetailsService(clientDetails());//设置客户端信息

            service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
            service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
            return service;
        }
    }

额外发现:

在扩展jwt令牌信息的时候,我们选择TokenEnhancer来进行增加信息,但在看源码的过程中,发现在DefaultUserAuthenticationConverter类中的 convertUserAuthentication方法,这个方法就是将authentication转换为map**(map就是token中的键值对!!!)**

所以之前拓展jwt信息可以不使用TokenEnhancer,而是重写 convertUserAuthentication方法,将authentication中的“user_info”添加到map中!!!然后就会根据map生成jwt令牌,并附带拓展信息。但是这样有一个弊端,就是你拓展信息不仅会出现在jwt令牌中,还会出现在token中。因为只要生成token就会调用convertUserAuthentication,所以生成jwt令牌时调用一次、生成token时又会调用一次。

如果你想让token的信息更丰富的话,倒是可以重写 convertUserAuthentication。但是只想让jwt令牌信息更丰富,还是老老实实添加tokenEnhancer。

调用链:DefaultTokenServices的createAccessToken(生成一个uuid value)->TokenEnhancer->JwtAccessTokenConverter的enhance(将token中的value改为jwt令牌)->JwtAccessTokenConverter的encode(生成jwt令牌)->DefaultAccessTokenConverter(产生生成令牌的原料map)->DefaultUserAuthenticationConverter(从Authentication中读取map,username与AUTHORITIES就是在这添加进去的)

token键值对形式:

{
    "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDE0OTQ1NzcsInVzZXJfbmFtZSI6IjEyMyIsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6ImViOWFlMWE5LTU2NDgtNGJmMC04NDZiLTlkM2QxZTJjNTVlNyIsImNsaWVudF9pZCI6IkhlYWx0aFBvcnRXZWJBcHAiLCJzY29wZSI6WyJhbGwiXX0.zqGJVy0LsoYysUmWgJCzYrOBsIDAmYn1UNM4R7S3w2g",
 "refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIxMjMiLCJzY29wZSI6WyJhbGwiXSwiYXRpIjoiZWI5YWUxYTktNTY0OC00YmYwLTg0NmItOWQzZDFlMmM1NWU3IiwiZXhwIjoxNzAxNjcxNzY0LCJhdXRob3JpdGllcyI6WyJwMSJdLCJqdGkiOiIxN2FjOGY1Mi1iYWRhLTRlYTctOGJmMi05MDllZGNmNWYzZTEiLCJjbGllbnRfaWQiOiJIZWFsdGhQb3J0V2ViQXBwIn0.oE-hfv-g1Xj4jpMCs7LIOUpxvZq57TFXQLPm-O7u-Tw",
 "tokenHead": "Bearer ",
 "expiresIn": 7199
 }

DefaultUserAuthenticationConverter源码:

public class DefaultUserAuthenticationConverter implements UserAuthenticationConverter {

	private Collection<? extends GrantedAuthority> defaultAuthorities;

	private UserDetailsService userDetailsService;

	//从authentication获取map作为生成token的原料
	public Map<String, ?> convertUserAuthentication(Authentication authentication) {
		Map<String, Object> response = new LinkedHashMap<String, Object>();
		response.put(USERNAME, authentication.getName());
		if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
			response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
		}
		return response;
	}

    //这是refresh_token特有的方法,就是根据refresh_token中的信息生成Authentication
	public Authentication extractAuthentication(Map<String, ?> map) {
		if (map.containsKey(USERNAME)) {
			Object principal = map.get(USERNAME);
			Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
			if (userDetailsService != null) {
				UserDetails user = userDetailsService.loadUserByUsername((String) map.get(USERNAME));
				authorities = user.getAuthorities();
				principal = user;
			}
			return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);
		}
		return null;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值