| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- package com.usky.vpp.client;
- import com.fasterxml.jackson.core.type.TypeReference;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.usky.vpp.config.VppUnProperties;
- import com.usky.vpp.config.VppUnPropertiesRegistry;
- import com.usky.vpp.config.VppUnTenantContext;
- import com.usky.vpp.util.VppUnMessageBuilder;
- import com.usky.vpp.util.VppUnPayloadHelper;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import org.springframework.util.StringUtils;
- import java.time.Instant;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * UN Token 缓存(按租户维度,TokenRequest 获取,默认约 30 分钟过期)
- */
- @Component
- public class VppUnTokenHolder {
- private static final Logger log = LoggerFactory.getLogger(VppUnTokenHolder.class);
- private final ConcurrentHashMap<Integer, TokenState> tokenStates = new ConcurrentHashMap<>();
- private final ConcurrentHashMap<Integer, ReentrantLock> locks = new ConcurrentHashMap<>();
- @Autowired
- private VppUnPropertiesRegistry propertiesRegistry;
- @Autowired
- private VppUnHttpExecutor httpExecutor;
- @Autowired
- private ObjectMapper objectMapper;
- public String getToken() {
- Integer tenantId = VppUnTenantContext.resolveTenantId();
- TokenState state = tokenStates.computeIfAbsent(tenantId, id -> createInitialState(id));
- if (!state.needsRefresh()) {
- return state.token;
- }
- ReentrantLock lock = locks.computeIfAbsent(tenantId, id -> new ReentrantLock());
- lock.lock();
- try {
- state = tokenStates.computeIfAbsent(tenantId, id -> createInitialState(id));
- if (!state.needsRefresh()) {
- return state.token;
- }
- refreshTokenInternal(tenantId);
- return state.token;
- } finally {
- lock.unlock();
- }
- }
- public void invalidate() {
- Integer tenantId = VppUnTenantContext.resolveTenantId();
- ReentrantLock lock = locks.computeIfAbsent(tenantId, id -> new ReentrantLock());
- lock.lock();
- try {
- tokenStates.remove(tenantId);
- } finally {
- lock.unlock();
- }
- }
- public void applyTokenResponse(Map<String, Object> response) {
- Integer tenantId = VppUnTenantContext.resolveTenantId();
- String newToken = VppUnPayloadHelper.getString(response, "token");
- if (!StringUtils.hasText(newToken)) {
- throw new IllegalStateException("TokenResponse 缺少 token");
- }
- VppUnProperties properties = propertiesRegistry.require(tenantId);
- int ttlMinutes = properties.getTokenTtlMinutes() != null ? properties.getTokenTtlMinutes() : 25;
- TokenState state = new TokenState(newToken, Instant.now().plusSeconds(ttlMinutes * 60L));
- tokenStates.put(tenantId, state);
- propertiesRegistry.updateToken(tenantId, newToken);
- }
- private TokenState createInitialState(Integer tenantId) {
- VppUnProperties properties = propertiesRegistry.get(tenantId);
- if (properties != null && StringUtils.hasText(properties.getToken())) {
- int ttlMinutes = properties.getTokenTtlMinutes() != null ? properties.getTokenTtlMinutes() : 25;
- return new TokenState(properties.getToken(), Instant.now().plusSeconds(ttlMinutes * 60L));
- }
- return new TokenState(null, Instant.EPOCH);
- }
- private void refreshTokenInternal(Integer tenantId) {
- VppUnProperties properties = propertiesRegistry.require(tenantId);
- Map<String, Object> request = VppUnMessageBuilder.buildTokenRequest(properties);
- String responseBody = httpExecutor.postRaw("TokenRequest", request, false);
- try {
- Map<String, Object> response = objectMapper.readValue(responseBody, new TypeReference<Map<String, Object>>() {
- });
- Integer code = VppUnPayloadHelper.getInteger(response, "code");
- if (code != null && code != 200) {
- throw new IllegalStateException("TokenRequest 失败: " + response.get("description"));
- }
- applyTokenResponse(response);
- log.info("租户 {} UN Token 已刷新", tenantId);
- } catch (IllegalStateException ex) {
- throw ex;
- } catch (Exception ex) {
- throw new IllegalStateException("TokenResponse 解析失败", ex);
- }
- }
- private static final class TokenState {
- private final String token;
- private final Instant expiresAt;
- private TokenState(String token, Instant expiresAt) {
- this.token = token;
- this.expiresAt = expiresAt;
- }
- private boolean needsRefresh() {
- return !StringUtils.hasText(token) || Instant.now().isAfter(expiresAt);
- }
- }
- }
|