diff --git a/apps/vben5/apps/app-antd/.env.development b/apps/vben5/apps/app-antd/.env.development index 0692ed288..7327d9a14 100644 --- a/apps/vben5/apps/app-antd/.env.development +++ b/apps/vben5/apps/app-antd/.env.development @@ -15,5 +15,6 @@ VITE_DEVTOOLS=false # 是否注入全局loading VITE_INJECT_APP_LOADING=true +VITE_GLOB_AUDIENCE="openid email address phone profile offline_access lingyun-abp-application" VITE_GLOB_CLIENT_ID=vue-admin-client VITE_GLOB_CLIENT_SECRET=1q2w3e* diff --git a/apps/vben5/apps/app-antd/src/adapter/request/index.ts b/apps/vben5/apps/app-antd/src/adapter/request/index.ts index cb10c655d..f75d2aea1 100644 --- a/apps/vben5/apps/app-antd/src/adapter/request/index.ts +++ b/apps/vben5/apps/app-antd/src/adapter/request/index.ts @@ -5,12 +5,14 @@ import { } from '@vben/request'; import { useAccessStore } from '@vben/stores'; +import { useTokenApi } from '@abp/account'; import { requestClient } from '@abp/request'; import { message } from 'ant-design-vue'; import { useAuthStore } from '#/store'; export function initRequestClient() { + const { refreshTokenApi } = useTokenApi(); /** * 重新认证逻辑 */ @@ -33,6 +35,16 @@ export function initRequestClient() { * 刷新token逻辑 */ async function doRefreshToken() { + const accessStore = useAccessStore(); + if (accessStore.refreshToken) { + const { accessToken, tokenType, refreshToken } = await refreshTokenApi({ + refreshToken: accessStore.refreshToken, + }); + const newToken = `${tokenType} ${accessToken}`; + accessStore.setAccessToken(newToken); + accessStore.setRefreshToken(refreshToken); + return newToken; + } return ''; } diff --git a/apps/vben5/apps/app-antd/src/store/auth.ts b/apps/vben5/apps/app-antd/src/store/auth.ts index 4061a971f..6ff7c5e47 100644 --- a/apps/vben5/apps/app-antd/src/store/auth.ts +++ b/apps/vben5/apps/app-antd/src/store/auth.ts @@ -6,7 +6,7 @@ import { useRouter } from 'vue-router'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; -import { tokenApi, userInfoApi } from '@abp/account'; +import { useTokenApi, useUserInfoApi } from '@abp/account'; import { useAbpStore } from '@abp/core'; import { notification } from 'ant-design-vue'; import { defineStore } from 'pinia'; @@ -15,6 +15,8 @@ import { getConfigApi } from '#/api/core/abp'; import { $t } from '#/locales'; export const useAuthStore = defineStore('auth', () => { + const { loginApi } = useTokenApi(); + const { getUserInfoApi } = useUserInfoApi(); const accessStore = useAccessStore(); const userStore = useUserStore(); const abpStore = useAbpStore(); @@ -35,7 +37,7 @@ export const useAuthStore = defineStore('auth', () => { let userInfo: null | UserInfo = null; try { loginLoading.value = true; - const loginResult = await tokenApi.loginApi(params as any); + const loginResult = await loginApi(params as any); const { accessToken, tokenType, refreshToken } = loginResult; // 如果成功获取到 accessToken if (accessToken) { @@ -93,7 +95,7 @@ export const useAuthStore = defineStore('auth', () => { async function fetchUserInfo() { let userInfo: ({ [key: string]: any } & UserInfo) | null = null; - const userInfoRes = await userInfoApi.getUserInfoApi(); + const userInfoRes = await getUserInfoApi(); const abpConfig = await getConfigApi(); userInfo = { userId: userInfoRes.sub, diff --git a/apps/vben5/packages/@abp/account/src/api/index.ts b/apps/vben5/packages/@abp/account/src/api/index.ts index e63b0f9b9..a082efc18 100644 --- a/apps/vben5/packages/@abp/account/src/api/index.ts +++ b/apps/vben5/packages/@abp/account/src/api/index.ts @@ -1,2 +1,2 @@ -export * as tokenApi from './token'; -export * as userInfoApi from './user'; +export { useTokenApi } from './useTokenApi'; +export { useUserInfoApi } from './useUserInfoApi'; diff --git a/apps/vben5/packages/@abp/account/src/api/token.ts b/apps/vben5/packages/@abp/account/src/api/token.ts deleted file mode 100644 index 212cc707c..000000000 --- a/apps/vben5/packages/@abp/account/src/api/token.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { - OAuthTokenResult, - PasswordTokenRequestModel, - TokenResult, -} from '../types'; - -import { useAppConfig } from '@vben/hooks'; - -import { requestClient } from '@abp/request'; - -/** - * 用户登录 - * @param request 参数 - * @returns 用户token - */ -export async function loginApi( - request: PasswordTokenRequestModel, -): Promise { - const { clientId, clientSecret } = useAppConfig( - import.meta.env, - import.meta.env.PROD, - ); - const result = await requestClient.post( - '/connect/token', - { - client_id: clientId, - client_secret: clientSecret, - grant_type: 'password', - password: request.password, - scope: - 'openid email address phone profile offline_access lingyun-abp-application', - username: request.username, - }, - { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - }, - ); - return { - accessToken: result.access_token, - expiresIn: result.expires_in, - refreshToken: result.refresh_token, - tokenType: result.token_type, - }; -} diff --git a/apps/vben5/packages/@abp/account/src/api/useTokenApi.ts b/apps/vben5/packages/@abp/account/src/api/useTokenApi.ts new file mode 100644 index 000000000..eeec1df4c --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/api/useTokenApi.ts @@ -0,0 +1,84 @@ +import type { + OAuthTokenRefreshModel, + OAuthTokenResult, + PasswordTokenRequestModel, + TokenResult, +} from '../types'; + +import { useAppConfig } from '@vben/hooks'; + +import { useRequest } from '@abp/request'; + +export function useTokenApi() { + const { cancel, request } = useRequest(); + /** + * 用户登录 + * @param input 参数 + * @returns 用户token + */ + async function loginApi( + input: PasswordTokenRequestModel, + ): Promise { + const { audience, clientId, clientSecret } = useAppConfig( + import.meta.env, + import.meta.env.PROD, + ); + const result = await request('/connect/token', { + data: { + client_id: clientId, + client_secret: clientSecret, + grant_type: 'password', + password: input.password, + scope: audience, + username: input.username, + }, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + method: 'POST', + }); + return { + accessToken: result.access_token, + expiresIn: result.expires_in, + refreshToken: result.refresh_token, + tokenType: result.token_type, + }; + } + + /** + * 刷新令牌 + * @param input 参数 + * @returns 用户token + */ + async function refreshTokenApi(input: OAuthTokenRefreshModel) { + const { audience, clientId, clientSecret } = useAppConfig( + import.meta.env, + import.meta.env.PROD, + ); + const result = await request('/connect/token', { + data: { + client_id: clientId, + client_secret: clientSecret, + grant_type: 'refresh_token', + refresh_token: input.refreshToken, + scope: audience, + }, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + method: 'POST', + }); + return { + accessToken: result.access_token, + expiresIn: result.expires_in, + refreshToken: result.refresh_token, + tokenType: result.token_type, + }; + } + + return { + cancel, + loginApi, + refreshTokenApi, + }; +} diff --git a/apps/vben5/packages/@abp/account/src/api/useUserInfoApi.ts b/apps/vben5/packages/@abp/account/src/api/useUserInfoApi.ts new file mode 100644 index 000000000..aa7c5adb3 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/api/useUserInfoApi.ts @@ -0,0 +1,29 @@ +import type { OAuthUserInfo, UserInfo } from '../types/user'; + +import { useRequest } from '@abp/request'; + +export function useUserInfoApi() { + const { cancel, request } = useRequest(); + + /** + * 获取用户信息 + */ + async function getUserInfoApi(): Promise { + const result = await request('/connect/userinfo', { + method: 'GET', + }); + return { + ...result, + emailVerified: result.email_verified, + givenName: result.given_name, + phoneNumberVerified: result.phone_number_verified, + preferredUsername: result.preferred_username, + uniqueName: result.unique_name, + }; + } + + return { + cancel, + getUserInfoApi, + }; +} diff --git a/apps/vben5/packages/@abp/account/src/api/user.ts b/apps/vben5/packages/@abp/account/src/api/user.ts deleted file mode 100644 index 87611be89..000000000 --- a/apps/vben5/packages/@abp/account/src/api/user.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { OAuthUserInfo, UserInfo } from '../types/user'; - -import { requestClient } from '@abp/request'; - -/** - * 获取用户信息 - */ -export async function getUserInfoApi(): Promise { - const result = await requestClient.get('/connect/userinfo'); - return { - ...result, - emailVerified: result.email_verified, - givenName: result.given_name, - phoneNumberVerified: result.phone_number_verified, - preferredUsername: result.preferred_username, - uniqueName: result.unique_name, - }; -} diff --git a/apps/vben5/packages/@abp/account/src/types/token.ts b/apps/vben5/packages/@abp/account/src/types/token.ts index b8bb274d3..e3436012c 100644 --- a/apps/vben5/packages/@abp/account/src/types/token.ts +++ b/apps/vben5/packages/@abp/account/src/types/token.ts @@ -32,6 +32,10 @@ interface TokenResult { /** 令牌类型 */ tokenType: string; } +interface OAuthTokenRefreshModel { + /** 刷新令牌 */ + refreshToken: string; +} /** oauth标准令牌返回结构 */ interface OAuthTokenResult { /** 访问令牌 */ @@ -45,6 +49,7 @@ interface OAuthTokenResult { } export type { + OAuthTokenRefreshModel, OAuthTokenResult, PasswordTokenRequest, PasswordTokenRequestModel, diff --git a/apps/vben5/packages/@abp/request/src/hooks/useRequest.ts b/apps/vben5/packages/@abp/request/src/hooks/useRequest.ts index 723e05352..a72170a95 100644 --- a/apps/vben5/packages/@abp/request/src/hooks/useRequest.ts +++ b/apps/vben5/packages/@abp/request/src/hooks/useRequest.ts @@ -1,7 +1,5 @@ import type { AxiosRequestConfig } from 'axios'; -import { onUnmounted } from 'vue'; - import { requestClient } from '@abp/request'; type HttpMethod = @@ -20,12 +18,7 @@ interface RequestConfig extends AxiosRequestConfig { method: HttpMethod; } -interface RequestLifeCycle { - /** 是否自动销毁令牌 */ - autoDestroy?: boolean; -} - -export function useRequest(options?: RequestLifeCycle) { +export function useRequest() { const controllers = new Set(); function request(url: string, config: RequestConfig): Promise { @@ -46,13 +39,6 @@ export function useRequest(options?: RequestLifeCycle) { controllers.clear(); } - onUnmounted(() => { - if (options?.autoDestroy === false) { - return; - } - cancel('The Component has Unmounted!'); - }); - return { cancel, request, diff --git a/apps/vben5/packages/types/global.d.ts b/apps/vben5/packages/types/global.d.ts index 11b3b3ced..599c76420 100644 --- a/apps/vben5/packages/types/global.d.ts +++ b/apps/vben5/packages/types/global.d.ts @@ -11,10 +11,14 @@ export interface VbenAdminProAppConfigRaw { VITE_GLOB_API_URL: string; VITE_GLOB_CLIENT_ID: string; VITE_GLOB_CLIENT_SECRET: string; + VITE_GLOB_AUTHORITY: string; + VITE_GLOB_AUDIENCE?: string; } export interface ApplicationConfig { apiURL: string; + authority: string; + audience?: string; clientId: string; clientSecret: string; }