fix(course-package): extract role_key from JWT sub roles objects

JWT sub.roles is an array of objects with role_key field, not plain
strings. Fix extractRoleKeys to map role_key from each role object.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-30 08:41:54 +08:00
parent 1ddeb21ca7
commit 894ca05566
2 changed files with 25 additions and 12 deletions
+3
View File
@@ -7,5 +7,8 @@ HUIKE_ADMIN_BASE_URL=https://admin.moicen.com
MOICEN_ADMIN_USER=
MOICEN_ADMIN_PASSWORD=
# 课包(course_package)测试依赖 MOICEN_E2E_UNIONID(共用 teacher/student unionid
# 测试通过 JWT roles 验证只有 TEACHER/SUPERVISOR 角色可访问课包 API。
# 可选:任意 HTTP 200 健康检查 URLCI 可在仓库 Settings → Variables 配置 MOICEN_HEALTHCHECK_URL
MOICEN_HEALTHCHECK_URL=
+22 -12
View File
@@ -6,21 +6,31 @@ const kcBase =
process.env.HUIKE_ADMIN_BASE_URL?.trim() || 'https://admin.moicen.com';
/**
* 从 JWT payload 中提取 roles 数组(可能嵌在 `sub` JSON 字段内)。
* 从 JWT payload 中提取 role_key 字符串数组(可能嵌在 `sub` JSON 字段内)。
* roles 是对象数组(含 `role_key` 字段),也可能在顶层。
*/
function extractRoles(payload: Record<string, unknown> | null): string[] {
function extractRoleKeys(payload: Record<string, unknown> | null): string[] {
if (!payload) return [];
if (Array.isArray(payload.roles)) return payload.roles as string[];
const subRaw = payload.sub;
if (typeof subRaw === 'string') {
try {
const sub = JSON.parse(subRaw) as Record<string, unknown>;
if (Array.isArray(sub.roles)) return sub.roles as string[];
} catch {
/* 非 JSON sub,忽略 */
const rawRoles: unknown[] =
(Array.isArray(payload.roles) ? payload.roles : []) as unknown[];
if (rawRoles.length === 0) {
const subRaw = payload.sub;
if (typeof subRaw === 'string') {
try {
const sub = JSON.parse(subRaw) as Record<string, unknown>;
if (Array.isArray(sub.roles)) {
rawRoles.push(...(sub.roles as unknown[]));
}
} catch {
/* 非 JSON sub,忽略 */
}
}
}
return [];
return rawRoles
.map((r) =>
typeof r === 'string' ? r : (r as Record<string, unknown>)?.role_key as string | undefined,
)
.filter((k): k is string => typeof k === 'string' && k.length > 0);
}
test.describe('课包(course_package', () => {
@@ -61,7 +71,7 @@ test.describe('课包(course_package', () => {
const payload = decodeJwtPayload(authToken!);
expect(payload, 'JWT 应可解码').not.toBeNull();
const roles = extractRoles(payload);
const roles = extractRoleKeys(payload);
const hasCoursePkgRole = roles.some((r) =>
['TEACHER', 'SUPERVISOR'].includes(r),
);