oauth2使用JWT存储token
- 使用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);
}