有没有办法配置Spring Security OAuth2以便它自动清除TokenStore?
我想不时删除过期的令牌。我已经看过InMemoryTokenStore代码,它不时地执行刷新。
但是JdbcTokenStore没有执行任何清除,所以谁负责从存储中删除已删除的令牌?
我已经实现了一个使用MongoDB作为存储的TokenStore,但我遇到了同样的问题。没有人从存储中删除过期的令牌。
答案 0 :(得分:2)
不幸的是,JdbcTokenStore
不会自动清除过期的令牌。清除旧令牌取决于你。
以下是我将如何添加这样一种机制的想法。
Expiration date
是OAuth2AccessToken
的一部分,它被保存为数据库中的序列化java对象。
为了检测OAuth2AccessToken
是否有资格删除,您需要从数据库中读取它并对其进行反序列化。
这可能导致您需要清除大量OAuth2AccessTokens的性能损失。
我的建议是将oauth_access_token
表扩展为类型expiration
(H2方言)的TIMESTAMP
列,以保存到期日期。
create table oauth_access_token (
token_id VARCHAR(256),
token LONGVARBINARY,
authentication_id VARCHAR(256),
user_name VARCHAR(256),
client_id VARCHAR(256),
authentication LONGVARBINARY,
refresh_token VARCHAR(256),
expiration TIMESTAMP
);
扩展JdbcTokenStore
并覆盖storeAccessToken
方法。不要忘记更改insertAccessTokenSql
以便在插入语句中使用新列expiration
。
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
String refreshToken = null;
if (token.getRefreshToken() != null) {
refreshToken = token.getRefreshToken().getValue();
}
if (readAccessToken(token.getValue())!=null) {
removeAccessToken(token.getValue());
}
jdbcTemplate.update(insertAccessTokenSql, new Object[] { extractTokenKey(token.getValue()),
new SqlLobValue(serializeAccessToken(token)), authenticationKeyGenerator.extractKey(authentication),
authentication.isClientOnly() ? null : authentication.getName(),
authentication.getOAuth2Request().getClientId(),
new SqlLobValue(serializeAuthentication(authentication)), extractTokenKey(refreshToken), token.getExpiration() }, new int[] {
Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.TIMESTAMP });
}
启用Spring Task Execution and Scheduling并添加清除旧令牌的预定方法。
@Scheduled(fixedRate = 10000)
public void purgeOldTokens() {
java.util.Date now = new Date();
jdbcTemplate.update("delete from oauth_access_token where expiration <?", now);
}
注意。这段代码只是展示了我的想法。我无法保证没有错误。您的代码可能并且应该与我的示例代码不同。
答案 1 :(得分:0)
@ksokol 非常感谢!
这是使用 CustomJdbcTokenStore 的工作示例
public class CustomJdbcTokenStore extends JdbcTokenStore {
private final JdbcTemplate jdbcTemplate;
private static final String INSERT_ACCESS_TOKEN_WITH_EXPIRATION_SQL = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token, expiration) values (?, ?, ?, ?, ?, ?, ?,?)";
private static final String INSERT_REFRESH_TOKEN_WITH_EXPIRATION_SQL = "insert into oauth_refresh_token (token_id, token, authentication, expiration) values (?, ?, ?, ?)";
public CustomJdbcTokenStore(DataSource dataSource) {
super(dataSource);
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
String refreshToken = getRefreshToken(token);
if (this.readAccessToken(token.getValue()) != null) {
this.removeAccessToken(token.getValue());
}
final DefaultAuthenticationKeyGenerator defaultAuthenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
this.jdbcTemplate.update(
INSERT_ACCESS_TOKEN_WITH_EXPIRATION_SQL,
new Object[]{this.extractTokenKey(token.getValue()),
new SqlLobValue(this.serializeAccessToken(token)),
defaultAuthenticationKeyGenerator.extractKey(authentication),
authentication.isClientOnly() ? null : authentication.getName(),
authentication.getOAuth2Request().getClientId(),
new SqlLobValue(this.serializeAuthentication(authentication)),
this.extractTokenKey(refreshToken), token.getExpiration()},
new int[]{Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.TIMESTAMP});
}
private String getRefreshToken(OAuth2AccessToken token) {
if (token.getRefreshToken() != null) {
return token.getRefreshToken().getValue();
}
return null;
}
@Override
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
final DefaultExpiringOAuth2RefreshToken oAuth2RefreshToken = (DefaultExpiringOAuth2RefreshToken) refreshToken;
this.jdbcTemplate.update(INSERT_REFRESH_TOKEN_WITH_EXPIRATION_SQL, new Object[]{this.extractTokenKey(refreshToken.getValue()), new SqlLobValue(this.serializeRefreshToken(refreshToken)), new SqlLobValue(this.serializeAuthentication(authentication)), oAuth2RefreshToken.getExpiration()}, new int[]{Types.VARCHAR, Types.BLOB, Types.BLOB, Types.TIMESTAMP});
}
}}