From 83a5b5d34102d82fcd7ebb8891d2550b86a33b0f Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 7 Jul 2025 09:09:44 +0800 Subject: [PATCH 1/2] feat(vben5): Use secure storage for oidc data --- .../apps/app-antd/src/auth/authService.ts | 53 ------------------- apps/vben5/apps/app-antd/src/store/auth.ts | 15 +++--- apps/vben5/packages/@abp/account/package.json | 2 + .../packages/@abp/account/src/hooks/index.ts | 1 + .../@abp/account/src/hooks/useOidcClient.ts | 43 +++++++++++++++ .../packages/@abp/account/src/utils/auth.ts | 53 +++++++++++++++++++ .../packages/@abp/account/src/utils/index.ts | 1 + 7 files changed, 108 insertions(+), 60 deletions(-) delete mode 100644 apps/vben5/apps/app-antd/src/auth/authService.ts create mode 100644 apps/vben5/packages/@abp/account/src/hooks/useOidcClient.ts create mode 100644 apps/vben5/packages/@abp/account/src/utils/auth.ts create mode 100644 apps/vben5/packages/@abp/account/src/utils/index.ts diff --git a/apps/vben5/apps/app-antd/src/auth/authService.ts b/apps/vben5/apps/app-antd/src/auth/authService.ts deleted file mode 100644 index aaeaa626b..000000000 --- a/apps/vben5/apps/app-antd/src/auth/authService.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { useAppConfig } from '@vben/hooks'; - -import { UserManager, WebStorageStateStore } from 'oidc-client-ts'; - -const { authority, audience, clientId, clientSecret, disablePKCE } = - useAppConfig(import.meta.env, import.meta.env.PROD); - -const userManager = new UserManager({ - authority, - client_id: clientId, - client_secret: clientSecret, - redirect_uri: `${window.location.origin}/signin-callback`, - response_type: 'code', - scope: audience, - post_logout_redirect_uri: `${window.location.origin}/`, - silent_redirect_uri: `${window.location.origin}/silent-renew.html`, - automaticSilentRenew: true, - loadUserInfo: true, - userStore: new WebStorageStateStore({ store: window.localStorage }), - disablePKCE, -}); - -export default { - async login() { - return userManager.signinRedirect(); - }, - - async logout() { - return userManager.signoutRedirect(); - }, - - async refreshToken() { - return userManager.signinSilent(); - }, - - async getAccessToken() { - const user = await userManager.getUser(); - return user?.access_token; - }, - - async isAuthenticated() { - const user = await userManager.getUser(); - return !!user && !user.expired; - }, - - async handleCallback() { - return userManager.signinRedirectCallback(); - }, - - async getUser() { - return userManager.getUser(); - }, -}; diff --git a/apps/vben5/apps/app-antd/src/store/auth.ts b/apps/vben5/apps/app-antd/src/store/auth.ts index e259121ca..7492529a5 100644 --- a/apps/vben5/apps/app-antd/src/store/auth.ts +++ b/apps/vben5/apps/app-antd/src/store/auth.ts @@ -10,6 +10,7 @@ import { preferences } from '@vben/preferences'; import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; import { + useOidcClient, usePhoneLoginApi, useProfileApi, useQrCodeLoginApi, @@ -21,7 +22,6 @@ import { notification } from 'ant-design-vue'; import { defineStore } from 'pinia'; import { useAbpConfigApi } from '#/api/core/useAbpConfigApi'; -import authService from '#/auth/authService'; import { $t } from '#/locales'; export const useAuthStore = defineStore('auth', () => { @@ -36,12 +36,13 @@ export const useAuthStore = defineStore('auth', () => { const userStore = useUserStore(); const abpStore = useAbpStore(); const router = useRouter(); + const oidcClient = useOidcClient(); const loginLoading = ref(false); async function refreshSession() { - if (await authService.getAccessToken()) { - const user = await authService.refreshToken(); + if (await oidcClient.getAccessToken()) { + const user = await oidcClient.refreshToken(); const newToken = `${user?.token_type} ${user?.access_token}`; accessStore.setAccessToken(newToken); if (user?.refresh_token) { @@ -61,12 +62,12 @@ export const useAuthStore = defineStore('auth', () => { } async function oidcLogin() { - await authService.login(); + await oidcClient.login(); } async function oidcCallback() { try { - const user = await authService.handleCallback(); + const user = await oidcClient.handleCallback(); return await _loginSuccess({ accessToken: user.access_token, tokenType: user.token_type, @@ -127,9 +128,9 @@ export const useAuthStore = defineStore('auth', () => { async function logout(redirect: boolean = true) { try { - if (await authService.getAccessToken()) { + if (await oidcClient.getAccessToken()) { accessStore.setAccessToken(null); - await authService.logout(); + await oidcClient.logout(); } } catch { // 不做任何处理 diff --git a/apps/vben5/packages/@abp/account/package.json b/apps/vben5/packages/@abp/account/package.json index 12f69cf26..0b92c7213 100644 --- a/apps/vben5/packages/@abp/account/package.json +++ b/apps/vben5/packages/@abp/account/package.json @@ -37,6 +37,8 @@ "@vueuse/core": "catalog:", "@vueuse/integrations": "catalog:", "ant-design-vue": "catalog:", + "oidc-client-ts": "catalog:", + "secure-ls": "catalog:", "vue": "catalog:*", "vue-router": "catalog:" } diff --git a/apps/vben5/packages/@abp/account/src/hooks/index.ts b/apps/vben5/packages/@abp/account/src/hooks/index.ts index 6c4512ba9..25bce3f27 100644 --- a/apps/vben5/packages/@abp/account/src/hooks/index.ts +++ b/apps/vben5/packages/@abp/account/src/hooks/index.ts @@ -1 +1,2 @@ export * from './useOAuthError'; +export * from './useOidcClient'; diff --git a/apps/vben5/packages/@abp/account/src/hooks/useOidcClient.ts b/apps/vben5/packages/@abp/account/src/hooks/useOidcClient.ts new file mode 100644 index 000000000..f4090b44e --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/hooks/useOidcClient.ts @@ -0,0 +1,43 @@ +import { userManager } from '../utils/auth'; + +export function useOidcClient() { + async function login() { + return userManager.signinRedirect(); + } + + async function logout() { + return userManager.signoutRedirect(); + } + + async function refreshToken() { + return userManager.signinSilent(); + } + + async function getAccessToken() { + const user = await userManager.getUser(); + return user?.access_token; + } + + async function isAuthenticated() { + const user = await userManager.getUser(); + return !!user && !user.expired; + } + + async function handleCallback() { + return userManager.signinRedirectCallback(); + } + + async function getUser() { + return userManager.getUser(); + } + + return { + login, + logout, + refreshToken, + getAccessToken, + isAuthenticated, + handleCallback, + getUser, + }; +} diff --git a/apps/vben5/packages/@abp/account/src/utils/auth.ts b/apps/vben5/packages/@abp/account/src/utils/auth.ts new file mode 100644 index 000000000..30a7d616f --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/utils/auth.ts @@ -0,0 +1,53 @@ +import { useAppConfig } from '@vben/hooks'; + +import { UserManager, WebStorageStateStore } from 'oidc-client-ts'; +import SecureLS from 'secure-ls'; + +const { authority, audience, clientId, clientSecret, disablePKCE } = + useAppConfig(import.meta.env, import.meta.env.PROD); + +const env = import.meta.env.PROD ? 'prod' : 'dev'; +const appVersion = import.meta.env.VITE_APP_VERSION; +const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`; + +const ls = new SecureLS({ + encodingType: 'aes', + encryptionSecret: import.meta.env.VITE_APP_STORE_SECURE_KEY, + isCompression: true, + // @ts-ignore secure-ls does not have a type definition for this + metaKey: `${namespace}-secure-oidc`, +}); +export const userManager = new UserManager({ + authority, + client_id: clientId, + client_secret: clientSecret, + redirect_uri: `${window.location.origin}/signin-callback`, + response_type: 'code', + scope: audience, + post_logout_redirect_uri: `${window.location.origin}/`, + silent_redirect_uri: `${window.location.origin}/silent-renew.html`, + automaticSilentRenew: true, + loadUserInfo: true, + userStore: new WebStorageStateStore({ + store: import.meta.env.DEV + ? localStorage + : { + length: ls.storage.length, + clear: ls.clear, + setItem(key, value) { + ls.set(key, value); + }, + getItem(key) { + return ls.get(key); + }, + key(index) { + const keys = ls.getAllKeys(); + return keys[index] ?? null; + }, + removeItem(key) { + ls.remove(key); + }, + }, + }), + disablePKCE, +}); diff --git a/apps/vben5/packages/@abp/account/src/utils/index.ts b/apps/vben5/packages/@abp/account/src/utils/index.ts new file mode 100644 index 000000000..269586ee8 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/utils/index.ts @@ -0,0 +1 @@ +export * from './auth'; From 8af8449be2a88f54c5a9b18efa24071a263a46ea Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 7 Jul 2025 09:11:27 +0800 Subject: [PATCH 2/2] feat(vben5): remove `oidc-client-ts` for app-antd --- apps/vben5/apps/app-antd/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/vben5/apps/app-antd/package.json b/apps/vben5/apps/app-antd/package.json index f13bb9e44..03fa292ee 100644 --- a/apps/vben5/apps/app-antd/package.json +++ b/apps/vben5/apps/app-antd/package.json @@ -64,7 +64,6 @@ "@vueuse/core": "catalog:", "ant-design-vue": "catalog:", "dayjs": "catalog:", - "oidc-client-ts": "catalog:", "pinia": "catalog:", "vue": "catalog:", "vue-router": "catalog:"