import { useUserStore } from '@/stores/user' export const REFRESH_TOKEN_URL = '/uaa/oauth/mobile/refresh_token' export type AuthPrincipal = { branchId?: string currentOrgId?: string mbNo?: string ip?: string loginIp?: string orgId?: string orgIds?: string[] roleIds?: string[] reqIpAddr?: string username?: string userId?: string userRealName?: string organizationName?: string orgName?: string org_name?: string currentOrgName?: string current_org_name?: string institutionName?: string institution_name?: string branchName?: string branch_name?: string deptName?: string dept_name?: string departmentName?: string department_name?: string unitName?: string unit_name?: string agencyName?: string agency_name?: string bankName?: string bank_name?: string organization?: unknown org?: unknown institution?: unknown branch?: unknown dept?: unknown department?: unknown unit?: unknown agency?: unknown bank?: unknown [key: string]: unknown } export type AuthTokenPayload = { token?: string access_token?: string refresh_token?: string refreshToken?: string token_type?: string expires_in?: number scope?: string principal?: AuthPrincipal } export type AuthTokenResponse = AuthTokenPayload & { data?: AuthTokenPayload } let refreshTokenPromise: Promise | null = null export function getAccessTokenFromResponse(response: AuthTokenResponse) { return ( response.data?.token || response.data?.access_token || response.token || response.access_token ) } export function getRefreshTokenFromResponse(response: AuthTokenResponse) { return ( response.data?.refresh_token || response.data?.refreshToken || response.refresh_token || response.refreshToken ) } export function getStoredAccessToken() { return useUserStore().token } export function getStoredRefreshToken() { return useUserStore().refreshToken } export function getAuthHeaders(headers?: Record, skipAuth = false) { const token = getStoredAccessToken() return { 'Content-Type': 'application/json', Accept: 'application/json', ...(!skipAuth && token ? { Authorization: `Bearer ${token}` } : {}), ...headers, } } export function saveAuthTokens(response: AuthTokenResponse) { const payload = getAuthPayloadFromResponse(response) const payloadForStorage = sanitizeAuthPayload(payload) const token = getAccessTokenFromResponse(response) const refreshToken = getRefreshTokenFromResponse(response) const principal = payload.principal if (!token) { throw new Error('接口未返回业务 token') } const userStore = useUserStore() userStore.setAuthTokens(token, refreshToken, payloadForStorage) userStore.setUserInfo({ username: principal?.username, realName: principal?.userRealName, organizationName: getOrganizationNameFromPrincipal(principal), }) return token } function getAuthPayloadFromResponse(response: AuthTokenResponse) { // 登录接口可能直接返回 token,也可能包一层 data;这里统一取真正的认证载荷。 if (isAuthPayload(response.data)) { return response.data } return response } function isAuthPayload(payload?: AuthTokenPayload): payload is AuthTokenPayload { return Boolean( payload && (payload.token || payload.access_token || payload.refresh_token || payload.refreshToken || payload.principal), ) } function sanitizeAuthPayload(payload: AuthTokenPayload): AuthTokenPayload { if (!payload.principal) return payload // 后端 principal 里会带 password 哈希,本地只保存业务需要的用户信息。 const { password: _password, ...principal } = payload.principal return { ...payload, principal, } } function getOrganizationNameFromPrincipal(principal?: AuthPrincipal) { if (!principal) return undefined return firstText( principal.organizationName, principal.orgName, principal.org_name, principal.currentOrgName, principal.current_org_name, principal.institutionName, principal.institution_name, principal.branchName, principal.branch_name, principal.deptName, principal.dept_name, principal.departmentName, principal.department_name, principal.unitName, principal.unit_name, principal.agencyName, principal.agency_name, principal.bankName, principal.bank_name, principal.organization, principal.org, principal.institution, principal.branch, principal.dept, principal.department, principal.unit, principal.agency, principal.bank, getNameFromRecord(principal.organization), getNameFromRecord(principal.org), getNameFromRecord(principal.institution), getNameFromRecord(principal.branch), getNameFromRecord(principal.dept), getNameFromRecord(principal.department), getNameFromRecord(principal.unit), getNameFromRecord(principal.agency), getNameFromRecord(principal.bank), ) } function getNameFromRecord(value: unknown) { if (!isRecord(value)) return undefined return firstText( value.name, value.organizationName, value.orgName, value.institutionName, value.branchName, value.deptName, value.departmentName, value.unitName, value.agencyName, value.bankName, ) } function firstText(...values: unknown[]) { for (const value of values) { if (typeof value !== 'string') continue const text = value.trim() if (text) return text } return undefined } function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null } export function clearAuthTokens() { useUserStore().clearToken() } export function refreshAccessToken(requestRefreshToken: () => Promise) { if (!refreshTokenPromise) { refreshTokenPromise = requestRefreshToken() .then(saveAuthTokens) .finally(() => { refreshTokenPromise = null }) } return refreshTokenPromise }