TokenStore:Persistence interface for OAuth2 tokens.(對於OAuth2令牌持久化介面)
官方文件
TokenStore 的預設實現有三種:
- InMemoryTokenStore
- JdbcTokenStore
- JwtTokenStore
此外,將會根據TokenStor的特性多自定義一種實現——RedisTokenStore
一、InMemoryTokenStore
1.1.概要
這個是OAuth2預設採用的實現方式。在單服務上可以體現出很好特效(即併發量不大,並且它在失敗的時候不會進行備份),大多專案都可以採用此方法。根據名字就知道了,是儲存在記憶體中,畢竟存在記憶體,而不是磁碟中,除錯簡易。
1.2.實現
既然InMemoryTokenStore是OAuth2預設實現,那麼就不需要我們再去配置,直接呼叫即可。
1.3.程式碼呼叫
@Autowired(required = false)
private TokenStore inMemoryTokenStore;
/**
* 端點(處理入口)
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(inMemoryTokenStore);
....
}
複製程式碼
1.4.測試呼叫訪問獲取Token
此處基於SpringBoot+Security的小demo,相關配置就不在本文太多出現,著重講解TokenStore
- spring security 預設授權認證端點:oauth/token
- 此處使用:grant_type—>password模式
二、JdbcTokenStore
2.1.概要
這個是基於JDBC的實現,令牌(Access Token)會儲存到資料庫。這個方式,可以在多個服務之間實現令牌共享。
2.2.實現
1).既然是JDBC,那麼肯定得需要一個資料來源。此處使用的是SpringBoot,因此配置了一個資料來源。所需jar依賴就不多說了。
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/security?useUnicode=yes&characterEncoding=UTF-8
username: catalpaFlat
password: catalpaFlat
複製程式碼
2).除了資料來源,那麼jdbc肯定得有庫表,因此OAuth2預設給出了表結構
Drop table if exists oauth_access_token;
create table oauth_access_token (
create_time timestamp default now(),
token_id VARCHAR(255),
token BLOB,
authentication_id VARCHAR(255),
user_name VARCHAR(255),
client_id VARCHAR(255),
authentication BLOB,
refresh_token VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Drop table if exists oauth_refresh_token;
create table oauth_refresh_token (
create_time timestamp default now(),
token_id VARCHAR(255),
token BLOB,
authentication BLOB
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
複製程式碼
而且JdbcTokenStore原始碼中也有很多關於表的操作:
3).配置JdbcTokenStore
@Autowired
private DataSource dataSource;
/**
* jdbc token 配置
*/
@Bean
public TokenStore jdbcTokenStore() {
Assert.state(dataSource != null, "DataSource must be provided");
return new JdbcTokenStore(dataSource);
}
複製程式碼
2.3.程式碼呼叫
@Autowired(required = false)
private TokenStore jdbcTokenStore;
/**
* 端點(處理入口)
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(jdbcTokenStore);
....
}
複製程式碼
2.4.測試呼叫訪問獲取Token
三、JwtTokenStore
3.1.概要
jwt全稱 JSON Web Token。這個實現方式不用管如何進行儲存(記憶體或磁碟),因為它可以把相關資訊資料編碼存放在令牌裡。JwtTokenStore 不會儲存任何資料,但是它在轉換令牌值以及授權資訊方面與 DefaultTokenServices 所扮演的角色是一樣的。
3.2.實現
既然jwt是將資訊存放在令牌中,那麼就得考慮其安全性,因此,OAuth2提供了JwtAccessTokenConverter實現,新增jwtSigningKey,以此生成祕鑰,以此進行簽名,只有jwtSigningKey才能獲取資訊。
/**
* jwt Token 配置, matchIfMissing = true
*
* @author : CatalpaFlat
*/
@Configuration
public class JwtTokenConfig {
private final Logger logger = LoggerFactory.getLogger(JwtTokenConfig.class);
@Value("${default.jwt.signing.key}")
private String defaultJwtSigningKey;
@Autowired
private CustomYmlConfig customYmlConfig;
public JwtTokenConfig() {logger.info("Loading JwtTokenConfig ...");}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
String jwtSigningKey = customYmlConfig.getSecurity().getOauth2s().getOuter().getJwtSigningKey();
Assert.state(StringUtils.isBlank(jwtSigningKey), "jwtSigningKey is not configured");
//祕籤
jwtAccessTokenConverter.setSigningKey(StringUtils.isBlank(jwtSigningKey) ? defaultJwtSigningKey : jwtSigningKey);
return jwtAccessTokenConverter;
}
}
複製程式碼
3.3.程式碼呼叫
@Autowired(required = false)
private TokenStore jwtTokenStore;
@Autowired(required = false)
private JwtAccessTokenConverter jwtAccessTokenConverter;
/**
* 端點(處理入口)
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(jwtTokenStore)
.accessTokenConverter(jwtAccessTokenConverter);
....
}
複製程式碼
3.4.測試呼叫訪問獲取Token
四、RedisTokenStore
4.1.概要
由於TokenStore作用就是對於OAuth2令牌持久化介面,而我們在實際開發中,對於記憶體的使用是慎之又慎,而對於儲存到資料庫也是根據專案需求進行調配。因此就想,可不可以用redis來進行儲存持久化我們的OAuth2令牌。偷偷瞄了一眼OAuth2還有那些實現了TokenStore的,找到了一個RedisTokenStore。
4.2.實現
記得配置redis
@Autowired
private RedisConnectionFactory redisConnectionFactory;
/**
* redis token 配置
*/
@Bean
public TokenStore redisTokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
複製程式碼
4.3.程式碼呼叫
@Autowired(required = false)
private TokenStore redisTokenStore;
/**
* 端點(處理入口)
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(redisTokenStore);
....
}
複製程式碼