Spring Security OAuth2:清除TokenStore

时间:2015-06-03 10:30:33

标签: spring oauth spring-security oauth-2.0 spring-security-oauth2

有没有办法配置Spring Security OAuth2以便它自动清除TokenStore?

我想不时删除过期的令牌。我已经看过InMemoryTokenStore代码,它不时地执行刷新。

但是JdbcTokenStore没有执行任何清除,所以谁负责从存储中删除已删除的令牌?

我已经实现了一个使用MongoDB作为存储的TokenStore,但我遇到了同样的问题。没有人从存储中删除过期的令牌。

2 个答案:

答案 0 :(得分:2)

不幸的是,JdbcTokenStore不会自动清除过期的令牌。清除旧令牌取决于你。 以下是我将如何添加这样一种机制的想法。

Expiration dateOAuth2AccessToken的一部分,它被保存为数据库中的序列化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});
    }
   
}}