From 76296b1623be65adad0488d97230a025c535296d Mon Sep 17 00:00:00 2001 From: lovefyf Date: Thu, 13 Aug 2026 01:11:33 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20toAuthUser=20=E5=AF=B9=20realm=5Faccess.?= =?UTF-8?q?roles/groups=20=E5=81=9A=E8=BF=90=E8=A1=8C=E6=97=B6=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E6=A0=A1=E9=AA=8C=EF=BC=88=E9=98=B2=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2=E5=AD=90=E4=B8=B2=E5=8C=B9=E9=85=8D=E8=B6=8A=E6=9D=83?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/keycloak-auth.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/shared/keycloak-auth.ts b/src/shared/keycloak-auth.ts index 0560221..54f452b 100644 --- a/src/shared/keycloak-auth.ts +++ b/src/shared/keycloak-auth.ts @@ -50,13 +50,27 @@ export async function verifyAccessToken(token: string): Promise { return payload; } +/** + * 运行时数组守卫:非数组(例如 Keycloak 把 realm_access.roles 误配成单值 String claim) + * 一律降为空数组——失败关闭。否则 `roles.includes('admin')` 会退化成 + * String.prototype.includes,"superadmin" 将子串命中 "admin" 造成越权。 + */ +function stringArray(v: unknown): string[] { + return Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : []; +} + export function toAuthUser(p: JWTPayload): AuthUser { const username = (p['preferred_username'] as string | undefined) ?? ''; + const realmAccess = p['realm_access']; const user: AuthUser = { id: p.sub ?? '', username, - roles: (p['realm_access'] as { roles?: string[] } | undefined)?.roles ?? [], - groups: (p['groups'] as string[] | undefined) ?? [], + roles: stringArray( + typeof realmAccess === 'object' && realmAccess !== null + ? (realmAccess as { roles?: unknown }).roles + : undefined, + ), + groups: stringArray(p['groups']), isService: username.startsWith('service-account-'), }; const azp = p['azp'];