R81 增加企微回调身份诊断

这个提交包含在:
2026-05-04 17:57:39 +08:00
父节点 c25a223945
当前提交 9dbac63744
共修改 3 个文件,包含 48 行新增和 1 行删除
+15 -1
查看文件
@@ -363,11 +363,25 @@ async function wecomAuthRoutes(fastify) {
const returnTo = sanitizeReturnTo(ctx.returnTo, fastify.config, request);
const profile = await exchangeWecomCode(fastify.config, code);
if (!profile.externalUserId) {
request.log.warn(
{
requestId: request.id,
mode,
hasUserId: false,
hasOpenId: Boolean(profile.externalOpenUserId),
hasDeviceId: Boolean(profile.deviceId),
},
"wecom callback missing internal user id",
);
throw new AppError({
code: "AUTH_003",
message: "企业微信认证失败",
statusCode: 401,
details: { wecom: "missing_user_id" },
details: {
wecom: "missing_user_id",
hasOpenId: Boolean(profile.externalOpenUserId),
mode,
},
});
}
@@ -177,6 +177,35 @@ describe("wecom auth routes R27", () => {
await app.close();
});
it("returns structured diagnostics when wecom callback has only open id", async () => {
mockWecomFetch({ userId: "", openId: "wecom-open-only" });
const app = await buildApp();
const state = signPayload({
exp: Date.now() + 60_000,
nonce: "nonce-openid-only",
returnTo: "/portal",
mode: "login",
}, JWT_SECRET);
const response = await app.inject({
method: "GET",
url: `/api/auth/wecom/callback?state=${encodeURIComponent(state)}&code=test-code`,
});
expect(response.statusCode).toBe(401);
expect(response.json().error).toEqual(expect.objectContaining({
code: "AUTH_003",
message: "企业微信认证失败",
details: expect.objectContaining({
wecom: "missing_user_id",
hasOpenId: true,
mode: "login",
}),
}));
await app.close();
});
it("creates bind audit log on successful wecom bind callback", async () => {
mockWecomFetch({ userId: "wecom-bind-1" });
const prisma = buildPrisma();