优化
This commit is contained in:
@@ -6,11 +6,10 @@ import { ApiError } from '@/api/http'
|
||||
import {
|
||||
FRONTEND_TO_MERCHANT_PERMISSION_CODES,
|
||||
TENANT_PERMISSION_GROUPS,
|
||||
getMerchantPermissionResources,
|
||||
getCurrentMerchantPermissionCodes,
|
||||
getMerchantPersonalProfile,
|
||||
getTenantProfile,
|
||||
updateMerchantPersonalProfile,
|
||||
type MerchantPermissionResource,
|
||||
} from '@/modules/tenant-management/public'
|
||||
import { clearSessionTokens, getAccessToken, getRefreshToken, persistTemporaryAccessToken, persistTokenPair } from '@/api/session'
|
||||
import { decodeMerchantToken, type MerchantJwtPayload } from '@/modules/auth/utils/jwt'
|
||||
@@ -41,15 +40,8 @@ const emptyProfile: ClientAccountProfile = {
|
||||
tenantName: '',
|
||||
}
|
||||
|
||||
function effectiveBackendPermissions(payload: MerchantJwtPayload, resources?: MerchantPermissionResource[]) {
|
||||
const jwtPermissions = new Set(payload.permissions ?? [])
|
||||
if (!resources) return jwtPermissions
|
||||
const activeResources = new Set(resources.filter((item) => item.status === 'ACTIVE').map((item) => item.permissionCode))
|
||||
return new Set([...jwtPermissions].filter((permission) => activeResources.has(permission)))
|
||||
}
|
||||
|
||||
function mapPermissions(payload: MerchantJwtPayload, resources?: MerchantPermissionResource[]) {
|
||||
const backendPermissions = effectiveBackendPermissions(payload, resources)
|
||||
function mapPermissions(backendPermissionCodes: string[] = []) {
|
||||
const backendPermissions = new Set(backendPermissionCodes)
|
||||
const result = new Set<string>(['dashboard:view', 'account:profile:view'])
|
||||
for (const permission of backendPermissions) {
|
||||
if (frontendPermissionCodes.has(permission)) result.add(permission)
|
||||
@@ -64,7 +56,7 @@ function currentUser(payload: MerchantJwtPayload, tenantName?: string): CurrentU
|
||||
name: payload.username,
|
||||
account: payload.username,
|
||||
tenantName: tenantName || `企业租户 ${payload.tenant_id}`,
|
||||
roles: payload.roles?.length ? [...payload.roles] : ['企业成员'],
|
||||
roles: [],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,14 +72,14 @@ export const useAuthStore = defineStore('client-auth', () => {
|
||||
const permissionCodes = ref<string[]>([])
|
||||
const sessionRestored = ref(false)
|
||||
|
||||
function applyToken(accessToken: string, resources?: MerchantPermissionResource[]) {
|
||||
function applyToken(accessToken: string) {
|
||||
const decoded = decodeMerchantToken(accessToken)
|
||||
payload.value = decoded
|
||||
token.value = accessToken
|
||||
user.value = currentUser(decoded, user.value?.tenantName)
|
||||
profile.value.username = decoded.username
|
||||
profile.value.realName = decoded.username
|
||||
permissionCodes.value = mapPermissions(decoded, resources)
|
||||
permissionCodes.value = mapPermissions()
|
||||
}
|
||||
|
||||
function clearSession() {
|
||||
@@ -131,12 +123,14 @@ export const useAuthStore = defineStore('client-auth', () => {
|
||||
|
||||
async function loadSessionContext() {
|
||||
if (!payload.value) return
|
||||
const [resources, tenant, personalProfile] = await Promise.all([
|
||||
getMerchantPermissionResources(),
|
||||
const currentPermissionCodes = await getCurrentMerchantPermissionCodes()
|
||||
const currentAccessToken = getAccessToken()
|
||||
if (currentAccessToken && currentAccessToken !== token.value) applyToken(currentAccessToken)
|
||||
permissionCodes.value = mapPermissions(currentPermissionCodes)
|
||||
const [tenant, personalProfile] = await Promise.all([
|
||||
getTenantProfile(),
|
||||
getMerchantPersonalProfile(),
|
||||
])
|
||||
permissionCodes.value = mapPermissions(payload.value, resources)
|
||||
user.value = currentUser(payload.value, tenant.tenantName)
|
||||
profile.value = {
|
||||
...profile.value,
|
||||
@@ -174,7 +168,7 @@ export const useAuthStore = defineStore('client-auth', () => {
|
||||
payload.value = decoded
|
||||
user.value = currentUser(decoded)
|
||||
profile.value = { ...emptyProfile, username: decoded.username, realName: decoded.username }
|
||||
permissionCodes.value = mapPermissions(decoded)
|
||||
permissionCodes.value = mapPermissions()
|
||||
sessionRestored.value = false
|
||||
try {
|
||||
await loadSessionContext()
|
||||
@@ -196,7 +190,7 @@ export const useAuthStore = defineStore('client-auth', () => {
|
||||
payload.value = decoded
|
||||
user.value = currentUser(decoded)
|
||||
profile.value = { ...emptyProfile, username: decoded.username, realName: decoded.username }
|
||||
permissionCodes.value = mapPermissions(decoded)
|
||||
permissionCodes.value = mapPermissions()
|
||||
sessionRestored.value = false
|
||||
try {
|
||||
await loadSessionContext()
|
||||
|
||||
@@ -13,12 +13,10 @@ const payload = {
|
||||
tenant_id: 2001,
|
||||
membership_id: 3001,
|
||||
app_code: 'MERCHANT',
|
||||
roles: ['MERCHANT_OWNER'],
|
||||
permissions: ['merchant:profile:view'],
|
||||
exp: 1900000000,
|
||||
}
|
||||
|
||||
test('decodes a merchant JWT payload for UI identity and permissions', () => {
|
||||
test('decodes a merchant JWT payload containing identity without roles or permissions', () => {
|
||||
assert.deepEqual(decodeMerchantToken(tokenFor(payload)), payload)
|
||||
})
|
||||
|
||||
@@ -29,3 +27,7 @@ test('rejects tokens from the platform application domain', () => {
|
||||
test('rejects malformed tokens', () => {
|
||||
assert.throws(() => decodeMerchantToken('not-a-jwt'), /登录凭证格式无效/)
|
||||
})
|
||||
|
||||
test('rejects expired tokens', () => {
|
||||
assert.throws(() => decodeMerchantToken(tokenFor({ ...payload, exp: 1 })), /登录状态已过期/)
|
||||
})
|
||||
|
||||
@@ -6,8 +6,6 @@ export interface MerchantJwtPayload {
|
||||
membership_id: number | string
|
||||
app_code: string
|
||||
client_type?: string
|
||||
roles?: string[]
|
||||
permissions?: string[]
|
||||
exp: number
|
||||
}
|
||||
|
||||
@@ -29,9 +27,10 @@ export function decodeMerchantToken(token: string): MerchantJwtPayload {
|
||||
const payload = value as Partial<MerchantJwtPayload>
|
||||
if (!payload.user_id || !payload.username || !payload.tenant_id || !payload.membership_id || !payload.exp) throw new Error()
|
||||
if (payload.app_code !== 'MERCHANT') throw new Error('账号不属于当前应用端')
|
||||
if (payload.exp * 1000 <= Date.now()) throw new Error('登录状态已过期')
|
||||
return payload as MerchantJwtPayload
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message === '账号不属于当前应用端') throw error
|
||||
if (error instanceof Error && ['账号不属于当前应用端', '登录状态已过期'].includes(error.message)) throw error
|
||||
throw new Error('登录凭证无法解析,请重新登录')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ test('declares the documented merchant role and member endpoints', () => {
|
||||
assert.match(source, /url: `\/merchant\/v1\/iam\/members\/\$\{membershipId\}\/status`/)
|
||||
assert.match(source, /url: `\/merchant\/v1\/iam\/members\/\$\{membershipId\}\/password`/)
|
||||
assert.match(source, /url: '\/merchant\/v1\/iam\/profile'/)
|
||||
assert.match(source, /url: '\/merchant\/v1\/iam\/authorization\/permissions'/)
|
||||
assert.match(authSource, /getCurrentMerchantPermissionCodes\(\)/)
|
||||
assert.doesNotMatch(authSource, /payload\.permissions/)
|
||||
assert.doesNotMatch(authSource, /payload\.roles/)
|
||||
})
|
||||
|
||||
test('supports tenant profile updates and authenticated qualification downloads', () => {
|
||||
|
||||
@@ -145,6 +145,10 @@ export function getMerchantPermissionResources() {
|
||||
return apiRequest<MerchantPermissionResource[]>({ method: 'GET', url: '/merchant/v1/iam/permissions' })
|
||||
}
|
||||
|
||||
export function getCurrentMerchantPermissionCodes() {
|
||||
return apiRequest<string[]>({ method: 'GET', url: '/merchant/v1/iam/authorization/permissions' })
|
||||
}
|
||||
|
||||
export function getMerchantPersonalProfile() {
|
||||
return apiRequest<MerchantPersonalProfile>({ method: 'GET', url: '/merchant/v1/iam/profile' })
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export {
|
||||
getMerchantPermissionResources,
|
||||
getCurrentMerchantPermissionCodes,
|
||||
getMerchantPersonalProfile,
|
||||
getTenantProfile,
|
||||
updateMerchantPersonalProfile,
|
||||
|
||||
Reference in New Issue
Block a user