为 Spring API 客户端服务存储 JWT
Storing an JWT for a Spring API client service
我有一个服务正在调用远程 API 来获取数据。
它通过服务帐户授权,我将 JWT-Token 存储在服务中作为 class 变量的请求。
当其中一种方法获得 401 响应时,服务会尝试进行身份验证并将新的 JWT 存储在旧变量中。
我可以使服务成为具有请求范围的 Bean,但我想避免这种情况。
有人可以帮助我使 JWT class 变量线程安全吗?
例如如果 2 个请求同时尝试更新 JWT 令牌会怎样?
如果所有请求的 JWT 令牌都相同,那么您可以使用 AtomicReference
。在进行远程调用之前使用 getToken()
并将值应用于请求 headers.
例如:
/**
* Initialize it with an expired {@link OAuthToken} so we don't ever need to make a '{@code null}' check.
*/
private final AtomicReference<OAuthToken> atomicRefToken = new AtomicReference<>(OAuthToken.expiredToken());
public OAuthToken getToken() {
if (atomicRefToken.get().isExpired()) {
atomicRefToken.set(this.fetchToken());
}
return atomicRefToken.get();
}
private OAuthToken fetchToken() {
// fetch token via some call
return new OAuthToken(....)
}
OAuthToken
class.
示例
public class OAuthToken implements Serializable {
public static final String TOKEN_TYPE_BEARER = "bearer";
public static final Long SPARE_SECONDS = 100L;
private final String tokenType;
private final String accessToken;
private final Long expiresIn;
private final LocalDateTime expiresAt;
public OAuthToken(@JsonProperty("token_type") @NonNull String tokenType,
@JsonProperty("access_token") @NonNull String accessToken,
@JsonProperty("expires_in") @NonNull Long expiresIn) {
this.tokenType = tokenType;
this.accessToken = accessToken;
this.expiresIn = expiresIn;
this.expiresAt = LocalDateTime.now().plus(expiresIn - SPARE_SECONDS, ChronoUnit.SECONDS);
}
/**
* Create a new instance where the token is expired.
*
* @return new instance
*/
public static OAuthToken expiredToken() {
return new OAuthToken(TOKEN_TYPE_BEARER, "expired", 0L);
}
public boolean isExpired() {
return LocalDateTime.now().isAfter(expiresAt);
}
public String value() {
return this.accessToken;
}
}
我有一个服务正在调用远程 API 来获取数据。 它通过服务帐户授权,我将 JWT-Token 存储在服务中作为 class 变量的请求。
当其中一种方法获得 401 响应时,服务会尝试进行身份验证并将新的 JWT 存储在旧变量中。 我可以使服务成为具有请求范围的 Bean,但我想避免这种情况。
有人可以帮助我使 JWT class 变量线程安全吗? 例如如果 2 个请求同时尝试更新 JWT 令牌会怎样?
如果所有请求的 JWT 令牌都相同,那么您可以使用 AtomicReference
。在进行远程调用之前使用 getToken()
并将值应用于请求 headers.
例如:
/**
* Initialize it with an expired {@link OAuthToken} so we don't ever need to make a '{@code null}' check.
*/
private final AtomicReference<OAuthToken> atomicRefToken = new AtomicReference<>(OAuthToken.expiredToken());
public OAuthToken getToken() {
if (atomicRefToken.get().isExpired()) {
atomicRefToken.set(this.fetchToken());
}
return atomicRefToken.get();
}
private OAuthToken fetchToken() {
// fetch token via some call
return new OAuthToken(....)
}
OAuthToken
class.
public class OAuthToken implements Serializable {
public static final String TOKEN_TYPE_BEARER = "bearer";
public static final Long SPARE_SECONDS = 100L;
private final String tokenType;
private final String accessToken;
private final Long expiresIn;
private final LocalDateTime expiresAt;
public OAuthToken(@JsonProperty("token_type") @NonNull String tokenType,
@JsonProperty("access_token") @NonNull String accessToken,
@JsonProperty("expires_in") @NonNull Long expiresIn) {
this.tokenType = tokenType;
this.accessToken = accessToken;
this.expiresIn = expiresIn;
this.expiresAt = LocalDateTime.now().plus(expiresIn - SPARE_SECONDS, ChronoUnit.SECONDS);
}
/**
* Create a new instance where the token is expired.
*
* @return new instance
*/
public static OAuthToken expiredToken() {
return new OAuthToken(TOKEN_TYPE_BEARER, "expired", 0L);
}
public boolean isExpired() {
return LocalDateTime.now().isAfter(expiresAt);
}
public String value() {
return this.accessToken;
}
}