80 lines
2.9 KiB
Java
80 lines
2.9 KiB
Java
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 作为「应用密钥权威源」的验签密钥提供方。<br><br>
|
|
* 解析优先级:<br>
|
|
* 1) 本库 application_info —— 覆盖全部「已颁发」应用,新增/重置密钥后即时生效;<br>
|
|
* 2) 配置式受信应用 {@code yh.app-auth.trusted-apps} —— 平台自身默认密钥(如 应用中心 100616)
|
|
* 兜底,使其即便尚未落库也可验签,避免「默认 appKey 未建行」导致验签失败。<br><br>
|
|
* 带 60s 本地 TTL 缓存,避免每次验签直打库(密钥变更最长 60s 后生效)。<br><br>
|
|
* 这样 UserBase 作为颁发方不依赖 Redis 预热、也不局限于 trustedApps 写死的少量密钥,
|
|
* 能够验签所有它已颁发的应用。
|
|
*/
|
|
public class UserBaseAppSecretProvider implements AppSecretProvider {
|
|
|
|
private final ApplicationInfoRepository repository;
|
|
private final Map<String, String> trustedApps;
|
|
private final ConcurrentHashMap<String, CacheEntry> 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;
|
|
}
|
|
}
|
|
}
|