基本的token参数配置
@Data
public class Oauth2Properties {
private Oauth2ClientProperties[] clients={};
}
@Data
public class Oauth2ClientProperties {
private String clientId;
private String clientSecret;
private int accessTokenValiditySeconds = 7200;
}
fuiou.security.oauth2-properties.clients[0].clientId=fuiou
fuiou.security.oauth2-properties.clients[0].clientSecret=fuiousecret
fuiou.security.oauth2-properties.clients[0].accessTokenValiditySeconds=7200
@Configuration
@EnableAuthorizationServer
public class FuiouAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private SecurityProperties securityProperties;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
InMemoryClientDetailsServiceBuilder builder=clients.inMemory();
if(ArrayUtils.isNotEmpty(securityProperties.getOauth2Properties().getClients())) {
for (Oauth2ClientProperties cofnig : securityProperties.getOauth2Properties().getClients()) {
builder.withClient(cofnig.getClientId())
.secret(cofnig.getClientSecret())
.accessTokenValiditySeconds(cofnig.getAccessTokenValiditySeconds())
.authorizedGrantTypes("refresh_token","password")
.scopes("all");
}
}
}
}
现在的token存储在内存中,一旦服务器重启,token就失效了。
让token持久化到redis中
@Configuration
public class TokenStoreConfig {
@Autowired
private RedisConnectionFactory connectionFactory;
@Bean
public TokenStore redisTokenStore() {
return new RedisTokenStore(connectionFactory);
}
}
@Autowired
private TokenStore redisTokenStore;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(redisTokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
使用jwt代码默认token
jwt的特点:
1、自包含 本身是有意义的,可以根据令牌解析出user信息,而之前的token是uuid生成的是无意义的,还要根据uuid去redis或session中去拿。
2、密签 用于数据签名
3、可扩展 可以在jwt中加一些自定义的信息
注意:jwt中不能放敏感的数据,如用户密码等。
整合jwt
@Configuration
public class TokenStoreConfig {
@Autowired
private RedisConnectionFactory connectionFactory;
@Bean
@ConditionalOnProperty(prefix = "fuiou.security.oauth2-properties",name = "storeType",havingValue = "redis")
public TokenStore redisTokenStore() {
return new RedisTokenStore(connectionFactory);
}
@Configuration
@ConditionalOnProperty(prefix = "fuiou.security.oauth2-properties",name = "storeType",havingValue = "jwt",matchIfMissing = true)
public static class JwtTokenConfig{
@Autowired
private SecurityProperties securityProperties;
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
/**
* 配置jwt签名
* @return
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter=new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey(securityProperties.getOauth2Properties().getJwtSigningKey());
return accessTokenConverter;
}
}
}
注意:注入两个TokenStore可能会冲突,使用了@ConditionalOnProperty注解。matchIfMissing = true的意思是没有匹配到也生效。
@ConditionalOnProperty(prefix = "fuiou.security.oauth2-properties",name = "storeType",havingValue = "jwt",matchIfMissing = true)这行的意思是如果配置了fuiou.security.oauth2-properties.storeType的值是jwt,或者没配这个属性,都生效。
重启下一,密码模式获取token

可以看到获取的都是jwt格式的token了。
扩展
public class FuiouJwtTokenEnhancer implements TokenEnhancer{
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String,Object> info=new HashMap<String,Object>();
info.put("company", "fuiou");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
return accessToken;
}
}
@Bean
@ConditionalOnMissingBean(name="jwtTokenEnhancer")
public TokenEnhancer jwtTokenEnhancer() {
return new FuiouJwtTokenEnhancer();
}
@Autowired(required = false)
private TokenEnhancer jwtTokenEnhancer;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(redisTokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
if(jwtAccessTokenConverter!=null && jwtTokenEnhancer!=null) {
TokenEnhancerChain enhancerChain=new TokenEnhancerChain();
List<TokenEnhancer> enhancers=new ArrayList<TokenEnhancer>();
enhancers.add(jwtTokenEnhancer);
enhancers.add(jwtAccessTokenConverter);
enhancerChain.setTokenEnhancers(enhancers);
endpoints
.tokenEnhancer(enhancerChain)
.accessTokenConverter(jwtAccessTokenConverter);
}
}
@PostMapping("/me")
public Object me(Authentication user){
return user;
}
但是访问/user/me接口发现返回的数据并没有包含额外增加的自定义数据。额外的数据需要我们自己解析。
解析jwt的pom
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
解析jwt
@PostMapping("/me")
public Object me(Authentication user,HttpServletRequest request) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException, UnsupportedEncodingException{
String header=request.getHeader("Authorization");
String token=StringUtils.substringAfter(header, "bearer ");
Claims claims=Jwts.parser().setSigningKey(securityProperties.getOauth2Properties().getJwtSigningKey().getBytes("utf-8"))
.parseClaimsJws(token).getBody();
String company=(String)claims.get("company");
log.info("company==>"+company);
return user;
}
刷新token
token过期后根据refresh_token重新获取token


网友评论