令牌有多种存储方式,每种方式都是实现了 TokenStore 接口
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
spring:
application:
name: security-demo
redis:
host: 127.0.0.1
port: 6379
# password: 没有不用写
lettuce:
# 连接池配置
pool:
# 连接池中的最小空闲连接,默认 0
min-idle: 0
# 连接池中的最大空闲连接,默认 8
max-idle: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制),默认 -1ms
max-wait: -1ms
# 连接池最大连接数(使用负值表示没有限制),默认 8
max-active: 8
@Configuration
public class RedisTokenStoreConfig {
// 注入 RedisConnectionFactory,用于连接 Redis
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public TokenStore redisTokenStore (){
return new RedisTokenStore(redisConnectionFactory);
}
}
// 注入redisTokenStore
@Resource(name = "redisTokenStore")
private TokenStore tokenStore;
// 使用密码模式需要配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
// 设置为redis 配置令牌存储策略
.tokenStore(tokenStore);
}
... 省略
JWT是JSON WEB TOKEN的缩写,它是基于 RFC 7519 标准定义的一种可以安全传输的的JSON对象,由于使用了数字签名,所以是可信任和安全的。
{
"alg": "HS256",
"typ": "JWT"
}
{
"exp": 1572682831,
"user_name": "macro",
"authorities": [
"admin"
],
"jti": "c1a0645a-28b5-4468-b4c7-9623131853af",
"client_id": "admin",
"scope": [
"all"
]
}
@Configuration
public class JwtTokenStoreConfig {
@Primary
@Bean("jwtTokenStore")
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("test_key");//配置JWT使用的秘钥
return accessTokenConverter;
}
}
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
// 注入redisTokenStore
/* @Resource(name = "redisTokenStore")
private TokenStore tokenStore;*/
// 改为JWT
@Resource(name = "jwtTokenStore")
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
// 使用密码模式需要配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
// 设置为redis 配置令牌存储策略
.tokenStore(tokenStore)
// 将值转为jwt格式
.accessTokenConverter(jwtAccessTokenConverter);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("admin")//配置client_id
.secret(passwordEncoder.encode("admin123456"))//配置client_secret
.accessTokenValiditySeconds(3600)//配置访问token的有效期
.refreshTokenValiditySeconds(864000)//配置刷新token的有效期
.redirectUris("http://www.baidu.com")//配置redirect_uri,用于授权成功后跳转
.scopes("all") // 配置申请的权限范围,授权页面会显示
.authorizedGrantTypes("authorization_code","password");//配置grant_type,表示授权类型 ,"refresh_token"
}
}
发现获取到的令牌已经变成了JWT令牌,将access_token拿到https://jwt.io/ 网站上去解析下可以获得其中内容。
在Spring Cloud Security 中使用oauth2时,如果令牌失效了,可以使用刷新令牌通过refresh_token的授权模式再次获取access_token。
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("admin")//配置client_id
.secret(passwordEncoder.encode("admin123456"))//配置client_secret
.accessTokenValiditySeconds(3600)//配置访问token的有效期
.refreshTokenValiditySeconds(864000)//配置刷新token的有效期
.redirectUris("http://www.baidu.com")//配置redirect_uri,用于授权成功后跳转
.scopes("all") // 配置申请的权限范围,授权页面会显示
.autoApprove(true) //自动授权配置
.authorizedGrantTypes("authorization_code","password","refresh_token");//配置grant_type,表示授权类型
}
有时候我们需要扩展JWT中存储的内容,这里我们在JWT中扩展一个key为enhance,value为enhance info的数据。
public class JwtTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String, Object> info = new HashMap<>();
info.put("enhance", "enhance info");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
return accessToken;
}
}
@Configuration
public class JwtTokenStoreConfig {
//省略代码...
@Bean
public JwtTokenEnhancer jwtTokenEnhancer() {
return new JwtTokenEnhancer();
}
}
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserService userService;
@Autowired
@Qualifier("jwtTokenStore")
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private JwtTokenEnhancer jwtTokenEnhancer;
/**
* 使用密码模式需要配置
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> delegates = new ArrayList<>();
delegates.add(jwtTokenEnhancer); //配置JWT的内容增强器
delegates.add(jwtAccessTokenConverter);
enhancerChain.setTokenEnhancers(delegates);
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore) //配置令牌存储策略
.accessTokenConverter(jwtAccessTokenConverter)
.tokenEnhancer(enhancerChain);
}
//省略代码...
}
{
"user_name": "macro",
"scope": [
"all"
],
"exp": 1572683821,
"authorities": [
"admin"
],
"jti": "1ed1b0d8-f4ea-45a7-8375-211001a51a9e",
"client_id": "admin",
"enhance": "enhance info"
}