package jnpf.util; import cn.hutool.cache.CacheUtil; import cn.hutool.cache.impl.TimedCache; import cn.hutool.crypto.digest.DigestUtil; import jnpf.base.UserInfo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; /** * 网关工具类 */ @Component @Slf4j @RequiredArgsConstructor public class GatewayUtil { private static final String PENDING_PREFIX = "jnpf:login-session:pending:"; private static final String TOKEN_MAPPING_PREFIX = "jnpf:login-session:token:"; private static final String TENANT_REGISTRY_KEY = "jnpf:login-session:tenants"; private static final long PENDING_TTL_SECONDS = 7 * 24 * 60 * 60L; private static final TimedCache renewLimit; private static final long TIMEOUT = 1000L * 60; private final RedisUtil redisUtil; private final RedisTemplate redisTemplate; static { renewLimit = CacheUtil.newTimedCache(TIMEOUT); // 一分钟清理一次无用数据 renewLimit.schedulePrune(TIMEOUT); } /** * 同一个TOKEN一分钟内只会续期一次 */ public void renewToken(String token){ if(renewLimit.containsKey(token)) { return; } UserProvider.renewTimeout(token); renewLimit.put(token, 0); enqueueSessionTouch(token); } private void enqueueSessionTouch(String token) { try { UserInfo userInfo = UserProvider.getUser(); if (userInfo == null || userInfo.getTokenTimeout() == null) { return; } Date now = DateUtil.getNowDate(); Date expireTime = DateUtil.dateAddMinutes(now, userInfo.getTokenTimeout()); String normalizedToken = token == null ? "" : token.trim(); if (normalizedToken.regionMatches(true, 0, "bearer", 0, "bearer".length())) { normalizedToken = normalizedToken.substring("bearer".length()).trim(); } String sessionId = DigestUtil.sha256Hex(normalizedToken); String eventId = RandomUtil.uuId(); Map event = new LinkedHashMap<>(); event.put("eventId", eventId); event.put("transitionId", eventId); event.put("eventType", "TOUCH"); event.put("sessionId", sessionId); event.put("userInfo", userInfo); event.put("eventTime", now); event.put("expireTime", expireTime); long ttl = Math.max(1, userInfo.getTokenTimeout() * 60L + 120L); redisUtil.insert(TOKEN_MAPPING_PREFIX + sessionId, "1", ttl); if (StringUtil.isNotEmpty(userInfo.getTenantId())) { redisTemplate.opsForSet().add(TENANT_REGISTRY_KEY, userInfo.getTenantId()); } redisUtil.insert(PENDING_PREFIX + eventId, JsonUtil.getObjectToStringAsDate(event), PENDING_TTL_SECONDS); } catch (Exception e) { log.warn("同步登录会话续期失败,不影响当前请求", e); } } }