Spring Security OAuth 2.x 生命周期结束后,是否计划在 Spring Security 5.x 中提供 TokenStore? 目前我们正在使用 JdbcTokenStore 来缓存令牌,稍后用于代表用户完成长时间运行的进程。
这是当前的应用程序设置:
当前有关代币的流程是:
应用程序客户端调用一些应用程序实例并触发长时间运行的进程,假设应用程序实例#0被调用。 Oauth 令牌在 API 调用中提供。
<sec:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
....
<oauth:resource-server id="resourceServerFilter" resource-id="springsec"
token-services-ref="customTokenServices" />
@Override
public OAuth2Authentication loadAuthentication(String tokenString) {
// Get an access token for the specified token string
OAuth2AccessToken token = readAccessToken(tokenString);
// Check if a valid access token has been obtained
if (token == null) {
logToAuditLogAndThrow("Invalid access token");
}
// Check if the token has expired and there is no refresh token
if (token.isExpired() && token.getRefreshToken() == null) {
tokenStore.removeAccessToken(token);
logToAuditLogAndThrow(MessageFormat.format("The access token has expired on {0}", token.getExpiration()));
}
// Check if an authentication for this token already exists in the token store
OAuth2Authentication auth = tokenStore.readAuthentication(token);
if (auth == null) {
// Create an authentication for the token and store it in the token store
TokenProperties tokenProperties = TokenProperties.fromToken(token);
auth = SecurityUtil.createAuthentication(tokenProperties.getClientId(), token.getScope(), SecurityUtil.getTokenUserInfo(token));
try {
LOGGER.info(MessageFormat.format(Messages.STORING_TOKEN_FOR_USER_0_WITH_EXPIRATION_TIME_1, tokenProperties.getUserName(),
token.getExpiresIn()));
tokenStore.storeAccessToken(token, auth);
} catch (DataIntegrityViolationException e) {
LOGGER.debug(Messages.ERROR_STORING_TOKEN_DUE_TO_INTEGRITY_VIOLATION, e);
// Ignoring the exception as the token and authentication are already persisted by another client.
}
}
return auth;
}
@Override
public OAuth2AccessToken readAccessToken(String tokenString) {
// Check if an access token for the received token string already exists in the token store
OAuth2AccessToken token = tokenStore.readAccessToken(tokenString);
if (token != null) {
LOGGER.debug("Stored token value: " + token.getValue());
LOGGER.debug("Stored token type: " + token.getTokenType());
LOGGER.debug("Stored token expires in: " + token.getExpiresIn());
} else {
token = tokenParserChain.parse(tokenString);
}
return token;
}
<sec:custom-filter ref="compositeUriAuthorizationFilter" position="LAST" />
接下来的步骤基本上描述了一步的作用
public OAuth2AccessToken getToken(String userName) {
OAuth2AccessToken token = null;
Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByUserName(userName);
for (OAuth2AccessToken tokenx : tokens) {
// If a token is already found, overwrite it if the new token:
// 1) has a refresh token, and the current token hasn't, or
// 2) expires later than the current token
if (token == null || ((tokenx.getRefreshToken() != null) && (token.getRefreshToken() == null))
|| (tokenx.getExpiresIn() > token.getExpiresIn())) {
token = tokenx;
}
}
return token;
}
private OAuth2AccessToken getValidToken(String userName) {
OAuth2AccessToken token = tokenService.getToken(userName);
if (token == null) {
throw new SLException(Messages.NO_VALID_TOKEN_FOUND, userName);
}
if (token.isExpired() && token.getRefreshToken() == null) {
tokenService.removeToken(token);
throw new SLException(Messages.TOKEN_EXPIRED, userName);
}
return token;
}
...
public CloudControllerClient getControllerClient(String userName) {
try {
return clientFactory.createClient(getValidToken(userName));
} catch (CloudOperationException e) {
throw new SLException(e, Messages.CANT_CREATE_CLIENT);
}
}
最诚挚的问候, 伯彦