This commit is contained in:
2026-08-20 18:02:38 +08:00
parent b55b049e77
commit 1cd8b6a473
210 changed files with 6974 additions and 825 deletions
@@ -53,7 +53,6 @@ public class GatewaySecurityConfig {
.withJwkSetUri(properties.jwkSetUri())
.jwsAlgorithms(algorithms -> {
algorithms.add(SignatureAlgorithm.RS256);
algorithms.add(SignatureAlgorithm.ES256);
})
.build();
decoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(
@@ -5,12 +5,14 @@ import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
import org.springframework.security.oauth2.jwt.Jwt;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
/** Validates the identity and authorization claims required by overseas APIs. */
final class RequiredClaimsJwtValidator implements OAuth2TokenValidator<Jwt> {
private static final List<String> REQUIRED_CLAIMS = List.of(
"sub", "tenant_id", "app_code", "permission_version");
"sub", "tenant_id", "app_code", "permission_version", "authorities");
@Override
public OAuth2TokenValidatorResult validate(Jwt jwt) {
@@ -21,6 +23,42 @@ final class RequiredClaimsJwtValidator implements OAuth2TokenValidator<Jwt> {
"invalid_token", "JWT 缺少必要声明: " + claim, null));
}
}
Long subject = longValue(jwt.getSubject());
Long tenantId = longValue(jwt.getClaims().get("tenant_id"));
Long permissionVersion = longValue(jwt.getClaims().get("permission_version"));
String appCode = String.valueOf(jwt.getClaims().get("app_code")).toUpperCase(Locale.ROOT);
if (subject == null || subject <= 0) {
return failure("JWT sub 必须是正整数用户 ID");
}
if (tenantId == null || tenantId < 0) {
return failure("JWT tenant_id 必须是非负整数客户范围");
}
if (permissionVersion == null || permissionVersion < 0) {
return failure("JWT permission_version 必须是非负整数");
}
if (!("PLATFORM".equals(appCode) && tenantId == 0L)
&& !("MERCHANT".equals(appCode) && tenantId > 0L)) {
return failure("JWT app_code 与 tenant_id 访问域不一致");
}
Object authorities = jwt.getClaims().get("authorities");
if (!(authorities instanceof Collection<?> values)
|| values.stream().anyMatch(value -> value == null || value.toString().isBlank())) {
return failure("JWT authorities 必须是权限列表");
}
return OAuth2TokenValidatorResult.success();
}
private static Long longValue(Object value) {
if (value instanceof Number number) return number.longValue();
if (value == null) return null;
try {
return Long.valueOf(value.toString());
} catch (NumberFormatException ignored) {
return null;
}
}
private static OAuth2TokenValidatorResult failure(String message) {
return OAuth2TokenValidatorResult.failure(new OAuth2Error("invalid_token", message, null));
}
}