From 88310e0ee1faf1b65e1fc909db488a681d5d84ba Mon Sep 17 00:00:00 2001 From: sunlei Date: Sun, 17 May 2026 16:45:19 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E4=B8=B2=E8=81=94WordPress?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antdv-next/src/api/core/auth.ts | 49 ++++++++++++++++++++++++ apps/web-antdv-next/src/api/request.ts | 7 ++++ apps/web-antdv-next/src/store/auth.ts | 42 +++++++++++++++++++- packages/stores/src/modules/access.ts | 15 ++++++++ 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/apps/web-antdv-next/src/api/core/auth.ts b/apps/web-antdv-next/src/api/core/auth.ts index fe1677c..6732416 100644 --- a/apps/web-antdv-next/src/api/core/auth.ts +++ b/apps/web-antdv-next/src/api/core/auth.ts @@ -16,6 +16,25 @@ export namespace AuthApi { data: string; status: number; } + + export interface WordpressAuthResult { + auth: { + nonce: string; + type: 'cookie'; + }; + user?: Record; + } +} + +interface ApiSuccessResponse { + code: number; + data: T; + msg: string; +} + +interface RawApiResponse { + data: ApiSuccessResponse; + status: number; } /** @@ -53,6 +72,36 @@ export async function logoutApi() { ); } +/** + * WordPress 自动认证 + */ +export async function wordpressLoginApi() { + const response = await baseRequestClient.post< + RawApiResponse + >( + '/wordpress/auth/login', + {}, + { + withCredentials: true, + }, + ); + + return response.data.data; +} + +/** + * 清理 WordPress 授权态 + */ +export async function wordpressLogoutApi() { + return baseRequestClient.post( + '/wordpress/auth/logout', + {}, + { + withCredentials: true, + }, + ); +} + /** * 获取用户权限码 */ diff --git a/apps/web-antdv-next/src/api/request.ts b/apps/web-antdv-next/src/api/request.ts index 5eac9b4..51c27cd 100644 --- a/apps/web-antdv-next/src/api/request.ts +++ b/apps/web-antdv-next/src/api/request.ts @@ -50,6 +50,7 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) { const accessStore = useAccessStore(); const authStore = useAuthStore(); accessStore.setAccessToken(null); + accessStore.setWordpressAuth(null); if ( preferences.app.loginExpiredMode === 'modal' && accessStore.isAccessChecked @@ -80,12 +81,18 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) { fulfilled: async (config) => { const accessStore = useAccessStore(); const token = formatToken(accessStore.accessToken); + const wordpressNonce = accessStore.wordpressAuth?.nonce; if (token) { config.headers.Authorization = token; } else { delete config.headers.Authorization; } + if (wordpressNonce && `${config.url || ''}`.includes('/wordpress/')) { + config.headers['X-WP-Nonce'] = wordpressNonce; + } else { + delete config.headers['X-WP-Nonce']; + } config.headers['Accept-Language'] = preferences.app.locale; return config; }, diff --git a/apps/web-antdv-next/src/store/auth.ts b/apps/web-antdv-next/src/store/auth.ts index e4c077c..9899e8a 100644 --- a/apps/web-antdv-next/src/store/auth.ts +++ b/apps/web-antdv-next/src/store/auth.ts @@ -10,7 +10,14 @@ import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; import { notification } from 'antdv-next'; import { defineStore } from 'pinia'; -import { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api'; +import { + getAccessCodesApi, + getUserInfoApi, + loginApi, + logoutApi, + wordpressLoginApi, + wordpressLogoutApi, +} from '#/api'; import { $t } from '#/locales'; export const useAuthStore = defineStore('auth', () => { @@ -61,6 +68,13 @@ export const useAuthStore = defineStore('auth', () => { url.searchParams.set('ktUserInfo', JSON.stringify(userStore.userInfo)); } + if (accessStore.wordpressAuth) { + url.searchParams.set( + 'ktWordpressAuth', + JSON.stringify(accessStore.wordpressAuth), + ); + } + return url.toString(); } catch { return target; @@ -108,11 +122,16 @@ export const useAuthStore = defineStore('auth', () => { fetchUserInfo(), getAccessCodesApi(), ]); + const wordpressAuth = await wordpressLoginApi(); userInfo = fetchUserInfoResult; userStore.setUserInfo(userInfo); accessStore.setAccessCodes(accessCodes); + accessStore.setWordpressAuth({ + ...wordpressAuth.auth, + user: wordpressAuth.user, + }); if (accessStore.loginExpired) { accessStore.setLoginExpired(false); @@ -132,6 +151,20 @@ export const useAuthStore = defineStore('auth', () => { }); } } + } catch (error) { + accessStore.setAccessToken(null); + accessStore.setAccessCodes([]); + accessStore.setWordpressAuth(null); + userStore.setUserInfo(null); + + try { + await wordpressLogoutApi(); + await logoutApi(); + } catch { + // 不做任何处理 + } + + throw error; } finally { loginLoading.value = false; } @@ -147,6 +180,12 @@ export const useAuthStore = defineStore('auth', () => { if (isLoggingOut.value) return; // 正在登出中, 说明已进入循环, 直接返回. isLoggingOut.value = true; // 设置 标识 + try { + await wordpressLogoutApi(); + } catch { + // 不做任何处理 + } + try { await logoutApi(); } catch { @@ -156,6 +195,7 @@ export const useAuthStore = defineStore('auth', () => { resetAllStores(); accessStore.setLoginExpired(false); + accessStore.setWordpressAuth(null); } // 回登录页带上当前路由地址 diff --git a/packages/stores/src/modules/access.ts b/packages/stores/src/modules/access.ts index b88242e..0722e0e 100644 --- a/packages/stores/src/modules/access.ts +++ b/packages/stores/src/modules/access.ts @@ -6,6 +6,12 @@ import { acceptHMRUpdate, defineStore } from 'pinia'; type AccessToken = null | string; +interface WordpressAuthState { + nonce: string; + type: 'cookie'; + user?: Record; +} + interface AccessState { /** * 权限码 @@ -43,6 +49,10 @@ interface AccessState { * 登录 accessToken */ refreshToken: AccessToken; + /** + * WordPress 授权态,真实 WordPress cookie 保存在后端 httpOnly cookie 中。 + */ + wordpressAuth: null | WordpressAuthState; } /** @@ -94,6 +104,9 @@ export const useAccessStore = defineStore('core-access', { setRefreshToken(token: AccessToken) { this.refreshToken = token; }, + setWordpressAuth(auth: null | WordpressAuthState) { + this.wordpressAuth = auth; + }, unlockScreen() { this.isLockScreen = false; this.lockScreenPassword = undefined; @@ -107,6 +120,7 @@ export const useAccessStore = defineStore('core-access', { 'accessCodes', 'isLockScreen', 'lockScreenPassword', + 'wordpressAuth', ], }, state: (): AccessState => ({ @@ -119,6 +133,7 @@ export const useAccessStore = defineStore('core-access', { lockScreenPassword: undefined, loginExpired: false, refreshToken: null, + wordpressAuth: null, }), });