chore(debug): add detailed org switch token diagnostics
Record before/after jwt org context decode details for org switch into console and localStorage, and surface actionable debug dialog when returned token lacks org context. Made-with: Cursor
This commit is contained in:
+53
-14
@@ -2,7 +2,7 @@ import { reactive } from "vue";
|
||||
import request from "~/utils/request";
|
||||
import { CurrentOrgId, HtyAuthToken, HtySudoToken } from "~/utils";
|
||||
import type { Organization } from "~/types";
|
||||
import { showFailToast } from "vant";
|
||||
import { showDialog, showFailToast } from "vant";
|
||||
|
||||
interface OrgState {
|
||||
currentOrgId?: string;
|
||||
@@ -16,25 +16,43 @@ const store = reactive<OrgState>({
|
||||
homepageMd: "",
|
||||
});
|
||||
|
||||
const parseCurrentOrgIdFromToken = (token: string): string | undefined => {
|
||||
type JwtPayloadDebug = {
|
||||
token_id?: string;
|
||||
current_org_id?: string;
|
||||
current_org_role_keys?: string[];
|
||||
};
|
||||
|
||||
type JwtDecodeResult = {
|
||||
payload?: JwtPayloadDebug;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
const decodeJwtPayload = (token: string): JwtDecodeResult => {
|
||||
try {
|
||||
const tokenParts = token.split(".");
|
||||
if (tokenParts.length < 2) return undefined;
|
||||
if (tokenParts.length < 2) {
|
||||
return { error: "invalid token parts" };
|
||||
}
|
||||
const payloadRaw = tokenParts[1].replace(/-/g, "+").replace(/_/g, "/");
|
||||
const payloadRawWithPadding = payloadRaw.padEnd(
|
||||
Math.ceil(payloadRaw.length / 4) * 4,
|
||||
"="
|
||||
);
|
||||
const payloadJson = decodeURIComponent(
|
||||
atob(payloadRawWithPadding)
|
||||
.split("")
|
||||
.map((char) => `%${(`00${char.charCodeAt(0).toString(16)}`).slice(-2)}`)
|
||||
.join("")
|
||||
);
|
||||
const binary = atob(payloadRawWithPadding);
|
||||
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
||||
const payloadJson = new TextDecoder("utf-8").decode(bytes);
|
||||
const payload = JSON.parse(payloadJson);
|
||||
return payload.current_org_id || undefined;
|
||||
} catch (_error) {
|
||||
return undefined;
|
||||
return {
|
||||
payload: {
|
||||
token_id: payload.token_id,
|
||||
current_org_id: payload.current_org_id,
|
||||
current_org_role_keys: payload.current_org_role_keys,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error: error instanceof Error ? error.message : "decode jwt payload failed",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,6 +72,10 @@ export default function useOrg() {
|
||||
};
|
||||
|
||||
const switchOrg = async (orgId: string) => {
|
||||
const beforeAuthToken = window.localStorage.getItem(HtyAuthToken) || "";
|
||||
const beforeDecodeResult = beforeAuthToken
|
||||
? decodeJwtPayload(beforeAuthToken)
|
||||
: { error: "missing auth token before switch" };
|
||||
const { r, d, e } = await request({
|
||||
url: "/api/v1/uc/org/switch",
|
||||
method: "POST",
|
||||
@@ -67,9 +89,26 @@ export default function useOrg() {
|
||||
showFailToast("机构切换失败:返回 token 非法");
|
||||
return false;
|
||||
}
|
||||
const tokenOrgId = parseCurrentOrgIdFromToken(d);
|
||||
const afterDecodeResult = decodeJwtPayload(d);
|
||||
const tokenOrgId = afterDecodeResult.payload?.current_org_id;
|
||||
const debugPayload = {
|
||||
switch_target_org_id: orgId,
|
||||
before: beforeDecodeResult,
|
||||
after: afterDecodeResult,
|
||||
response_error: e,
|
||||
response_ok: r,
|
||||
returned_token_length: d.length,
|
||||
role_keys_count: afterDecodeResult.payload?.current_org_role_keys?.length || 0,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
window.localStorage.setItem("OrgSwitchDebug", JSON.stringify(debugPayload));
|
||||
console.warn("[OrgSwitchDebug]", debugPayload);
|
||||
|
||||
if (!tokenOrgId) {
|
||||
showFailToast("机构切换失败:token 缺少机构上下文");
|
||||
showDialog({
|
||||
title: "机构切换调试信息",
|
||||
message: "token 缺少机构上下文,请打开 vConsole 查看 [OrgSwitchDebug]",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
window.localStorage.setItem(HtyAuthToken, d);
|
||||
|
||||
Reference in New Issue
Block a user