- 使用jwt的好處
token生成的其實就是一個UUID,和業務沒有絲毫的關系,這樣帶來最大的問題,就是需要人工持久化處理token(像處理分布式下的sessionId一樣)。但是jwt就不需要,因為自包含,所以token里有身份驗證信息,不需要做后台持久化處理,前端每次請求被保護的資源時請求頭里帶上該token就可以實現。
- 使用 JWT
將 TokenStore 和 JwtAccessTokenConverter Bean 被 spring 托管
/**
* JWT token 儲存
*
* @return
*/
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
/**
* JWT token 生成處理:指定簽名
*
* @return
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("zl");
return jwtAccessTokenConverter;
}
tokenStore方法返回一個TokenStore對象的子對象JwtTokenStore,供給認證服務器取來給授權服務器端點配置器,通俗點就是讓OauthAuthorizationServerConfigurerAdapter(oauth授權服務器)能注入到值。
jwtAccessTokenConverter方法是根據簽名生成JwtToken,同樣也需要在OauthAuthorizationServerConfigurerAdapter類里注入。
/**
* 認證服務器
*/
@Configuration
@EnableAuthorizationServer
public class OauthAuthorizationServerConfigurerAdapter extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
super.configure(security);
}
/**
* 客戶端配置(給誰發令牌)
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient(ConsParams.Auth.GET_CLIENT_ID)
.secret(ConsParams.Auth.GET_SECRET)
//有效時間 2小時
.accessTokenValiditySeconds(ConsParams.Auth.GET_TOKEN_VALIDITY_SECONDS)
//密碼授權模式和刷新令牌
.authorizedGrantTypes(ConsParams.Auth.GE_TAUTHORIZED_GRANT_TYPES)
.scopes(ConsParams.Auth.GE_TSCOPES);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.accessTokenConverter(jwtAccessTokenConverter);
}
}
}
endpoints添加了accessTokenConverter屬性,它規定了token生成器是jwtAccessTokenConverter,並按照我們設置的簽名來生成。
發送請求獲取 token
獲取資源
- JWT 進行擴展
新建擴展類 JwtTokenEnhancer 繼承 TokenEnhancer
/**
* Jwt token 擴展
*/
public class JwtTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
Map<String,Object> info = new HashMap<>();
// 添加到 token 字符串里面的數據
info.put("show","zhang");
//設置附加信息
((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(info);
return oAuth2AccessToken;
}
}
將 JwtTokenEnhancer 類被 spring 托管
@Bean
public TokenEnhancer jwtTokenEnhancer(){
return new JwtTokenEnhancer();
}
修改 OauthAuthorizationServerConfigurerAdapter oauth認證服務器配置類
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
// token增強器鏈對象
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> enhancerList = new ArrayList<>();
enhancerList.add(jwtTokenEnhancer);
enhancerList.add(jwtAccessTokenConverter);
enhancerChain.setTokenEnhancers(enhancerList);
endpoints
.tokenEnhancer(enhancerChain)
.accessTokenConverter(jwtAccessTokenConverter);
}
現在就可以把數據添加到token里面了
- 解析 JWT
導包
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
寫個解析接口
@GetMapping("/userInfo")
public ServerResponse getCurrentUser(Authentication user, HttpServletRequest request) throws UnsupportedEncodingException {
String s = user.getPrincipal().toString();
String name = user.getName();
String header = request.getHeader("Authorization");
String token = StringUtils.substringAfter(header,"bearer ");
Claims body = Jwts.parser().setSigningKey(ConsParams.Auth.GET_SIGNING_KEY.getBytes("UTF-8"))
.parseClaimsJws(token).getBody();
String username = (String) body.get("username");
log.info("解析token獲取到的username為{}",username);
log.info("從Authentication里獲取到的username為{}",s);
log.info("從Authentication里獲取到的username為{}",name);
return ServerResponse.createBySuccess(user);
}