package com.yunhai.flowcenter.service; import com.fasterxml.jackson.databind.JsonNode; import com.yunhai.platform.apistd.BizException; import com.yunhai.platform.openapi.base.OpenApiAppClient; import com.yunhai.platform.utils.exception.ErrorCode; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; /** * 调用应用主体解析(D02/D09/D11:appKey 是验签凭据,不是主体)。 * *
主体=UserBase {@code application_info} 主键 id(稳定整型主键,appKey 可重置/复用不影响它)。 * 加 {@link #SOURCE_PREFIX} 前缀落库,与未来可能引入的 UUID 主体空间不撞。 * 不可达、查无、缺主键一律拒绝,不回退 appKey/数字自增猜测。
*/ @Service @RequiredArgsConstructor public class FlowSourcePrincipalResolver { /** 来源主体列(varchar(36))的命名空间前缀:标明"id 来自 UserBase 应用注册表主键"。 */ public static final String SOURCE_PREFIX = "ub-app:"; private final OpenApiAppClient appClient; /** 稳定主体字符串;appId 缺失即拒(调用方不得用猜测值补全)。 */ public static String sourcePrincipalIdOf(Integer appId) { if (appId == null || appId <= 0) { throw new BizException(ErrorCode.UNAUTHORIZED, "调用应用主体不可解析"); } return SOURCE_PREFIX + appId; } public Principal resolve(String authenticatedAppKey) { if (authenticatedAppKey == null || authenticatedAppKey.trim().isEmpty()) { throw new BizException(ErrorCode.UNAUTHORIZED, "缺少已认证的调用应用"); } JsonNode app; try { app = appClient.getAppByKey(authenticatedAppKey.trim()); } catch (RuntimeException unavailable) { throw new BizException(ErrorCode.UNAUTHORIZED, "调用应用主体解析不可用,请稍后重试"); } if (app == null || app.isNull() || !app.path("id").isIntegralNumber() || !app.path("id").canConvertToInt()) { throw new BizException(ErrorCode.UNAUTHORIZED, "调用应用主体不可解析"); } Integer appId = app.path("id").intValue(); return new Principal(sourcePrincipalIdOf(appId), appId, authenticatedAppKey.trim(), app.path("appCode").isTextual() ? app.path("appCode").textValue() : null); } @lombok.RequiredArgsConstructor public static class Principal { public final String id; public final Integer appId; public final String appKey; public final String appCode; } }