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:
@@ -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 健康检查 URL(CI 可在仓库 Settings → Variables 配置 MOICEN_HEALTHCHECK_URL)
|
||||
MOICEN_HEALTHCHECK_URL=
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user