package com.yunhai.userbase.config; import com.yunhai.platform.appauth.AppAuthProperties; import com.yunhai.platform.appauth.AppSecretProvider; import com.yunhai.userbase.entity.ApplicationInfo; import com.yunhai.userbase.repository.ApplicationInfoRepository; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * UserBase 作为「应用密钥权威源」的验签密钥提供方。

* 解析优先级:
* 1) 本库 application_info —— 覆盖全部「已颁发」应用,新增/重置密钥后即时生效;
* 2) 配置式受信应用 {@code yh.app-auth.trusted-apps} —— 平台自身默认密钥(如 应用中心 100616) * 兜底,使其即便尚未落库也可验签,避免「默认 appKey 未建行」导致验签失败。

* 带 60s 本地 TTL 缓存,避免每次验签直打库(密钥变更最长 60s 后生效)。

* 这样 UserBase 作为颁发方不依赖 Redis 预热、也不局限于 trustedApps 写死的少量密钥, * 能够验签所有它已颁发的应用。 */ public class UserBaseAppSecretProvider implements AppSecretProvider { private final ApplicationInfoRepository repository; private final Map trustedApps; private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); private static final long TTL_MS = 60_000L; public UserBaseAppSecretProvider(ApplicationInfoRepository repository, AppAuthProperties properties) { this.repository = repository; this.trustedApps = properties.getTrustedApps(); } @Override public String getSecret(String appKey) { if (appKey == null) { return null; } long now = System.currentTimeMillis(); CacheEntry hit = cache.get(appKey); if (hit != null && now - hit.ts < TTL_MS) { return hit.secret; } String secret = null; try { Integer id = parse(appKey); if (id != null) { ApplicationInfo info = repository.findByAppKey(id); if (info != null && info.getAppSecret() != null && !info.getAppSecret().trim().isEmpty()) { secret = info.getAppSecret(); } } } catch (Exception ignored) { // 查询异常不阻断,继续走配置兜底 } if (secret == null) { secret = trustedApps.get(appKey); } cache.put(appKey, new CacheEntry(now, secret)); return secret; } private static Integer parse(String appKey) { try { return Integer.parseInt(appKey.trim()); } catch (NumberFormatException e) { return null; } } private static final class CacheEntry { final long ts; final String secret; CacheEntry(long ts, String secret) { this.ts = ts; this.secret = secret; } } }