Browse Source

♻️ feat: refactoring oauth api.

pull/1076/head
colin 1 year ago
parent
commit
804d14e29b
  1. 1
      apps/vben5/apps/app-antd/.env.development
  2. 12
      apps/vben5/apps/app-antd/src/adapter/request/index.ts
  3. 8
      apps/vben5/apps/app-antd/src/store/auth.ts
  4. 4
      apps/vben5/packages/@abp/account/src/api/index.ts
  5. 46
      apps/vben5/packages/@abp/account/src/api/token.ts
  6. 84
      apps/vben5/packages/@abp/account/src/api/useTokenApi.ts
  7. 29
      apps/vben5/packages/@abp/account/src/api/useUserInfoApi.ts
  8. 18
      apps/vben5/packages/@abp/account/src/api/user.ts
  9. 5
      apps/vben5/packages/@abp/account/src/types/token.ts
  10. 16
      apps/vben5/packages/@abp/request/src/hooks/useRequest.ts
  11. 4
      apps/vben5/packages/types/global.d.ts

1
apps/vben5/apps/app-antd/.env.development

@ -15,5 +15,6 @@ VITE_DEVTOOLS=false
# 是否注入全局loading # 是否注入全局loading
VITE_INJECT_APP_LOADING=true 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_ID=vue-admin-client
VITE_GLOB_CLIENT_SECRET=1q2w3e* VITE_GLOB_CLIENT_SECRET=1q2w3e*

12
apps/vben5/apps/app-antd/src/adapter/request/index.ts

@ -5,12 +5,14 @@ import {
} from '@vben/request'; } from '@vben/request';
import { useAccessStore } from '@vben/stores'; import { useAccessStore } from '@vben/stores';
import { useTokenApi } from '@abp/account';
import { requestClient } from '@abp/request'; import { requestClient } from '@abp/request';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { useAuthStore } from '#/store'; import { useAuthStore } from '#/store';
export function initRequestClient() { export function initRequestClient() {
const { refreshTokenApi } = useTokenApi();
/** /**
* *
*/ */
@ -33,6 +35,16 @@ export function initRequestClient() {
* token逻辑 * token逻辑
*/ */
async function doRefreshToken() { 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 ''; return '';
} }

8
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 { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; 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 { useAbpStore } from '@abp/core';
import { notification } from 'ant-design-vue'; import { notification } from 'ant-design-vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
@ -15,6 +15,8 @@ import { getConfigApi } from '#/api/core/abp';
import { $t } from '#/locales'; import { $t } from '#/locales';
export const useAuthStore = defineStore('auth', () => { export const useAuthStore = defineStore('auth', () => {
const { loginApi } = useTokenApi();
const { getUserInfoApi } = useUserInfoApi();
const accessStore = useAccessStore(); const accessStore = useAccessStore();
const userStore = useUserStore(); const userStore = useUserStore();
const abpStore = useAbpStore(); const abpStore = useAbpStore();
@ -35,7 +37,7 @@ export const useAuthStore = defineStore('auth', () => {
let userInfo: null | UserInfo = null; let userInfo: null | UserInfo = null;
try { try {
loginLoading.value = true; loginLoading.value = true;
const loginResult = await tokenApi.loginApi(params as any); const loginResult = await loginApi(params as any);
const { accessToken, tokenType, refreshToken } = loginResult; const { accessToken, tokenType, refreshToken } = loginResult;
// 如果成功获取到 accessToken // 如果成功获取到 accessToken
if (accessToken) { if (accessToken) {
@ -93,7 +95,7 @@ export const useAuthStore = defineStore('auth', () => {
async function fetchUserInfo() { async function fetchUserInfo() {
let userInfo: ({ [key: string]: any } & UserInfo) | null = null; let userInfo: ({ [key: string]: any } & UserInfo) | null = null;
const userInfoRes = await userInfoApi.getUserInfoApi(); const userInfoRes = await getUserInfoApi();
const abpConfig = await getConfigApi(); const abpConfig = await getConfigApi();
userInfo = { userInfo = {
userId: userInfoRes.sub, userId: userInfoRes.sub,

4
apps/vben5/packages/@abp/account/src/api/index.ts

@ -1,2 +1,2 @@
export * as tokenApi from './token'; export { useTokenApi } from './useTokenApi';
export * as userInfoApi from './user'; export { useUserInfoApi } from './useUserInfoApi';

46
apps/vben5/packages/@abp/account/src/api/token.ts

@ -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<TokenResult> {
const { clientId, clientSecret } = useAppConfig(
import.meta.env,
import.meta.env.PROD,
);
const result = await requestClient.post<OAuthTokenResult>(
'/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,
};
}

84
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<TokenResult> {
const { audience, clientId, clientSecret } = useAppConfig(
import.meta.env,
import.meta.env.PROD,
);
const result = await request<OAuthTokenResult>('/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<OAuthTokenResult>('/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,
};
}

29
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<UserInfo> {
const result = await request<OAuthUserInfo>('/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,
};
}

18
apps/vben5/packages/@abp/account/src/api/user.ts

@ -1,18 +0,0 @@
import type { OAuthUserInfo, UserInfo } from '../types/user';
import { requestClient } from '@abp/request';
/**
*
*/
export async function getUserInfoApi(): Promise<UserInfo> {
const result = await requestClient.get<OAuthUserInfo>('/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,
};
}

5
apps/vben5/packages/@abp/account/src/types/token.ts

@ -32,6 +32,10 @@ interface TokenResult {
/** 令牌类型 */ /** 令牌类型 */
tokenType: string; tokenType: string;
} }
interface OAuthTokenRefreshModel {
/** 刷新令牌 */
refreshToken: string;
}
/** oauth标准令牌返回结构 */ /** oauth标准令牌返回结构 */
interface OAuthTokenResult { interface OAuthTokenResult {
/** 访问令牌 */ /** 访问令牌 */
@ -45,6 +49,7 @@ interface OAuthTokenResult {
} }
export type { export type {
OAuthTokenRefreshModel,
OAuthTokenResult, OAuthTokenResult,
PasswordTokenRequest, PasswordTokenRequest,
PasswordTokenRequestModel, PasswordTokenRequestModel,

16
apps/vben5/packages/@abp/request/src/hooks/useRequest.ts

@ -1,7 +1,5 @@
import type { AxiosRequestConfig } from 'axios'; import type { AxiosRequestConfig } from 'axios';
import { onUnmounted } from 'vue';
import { requestClient } from '@abp/request'; import { requestClient } from '@abp/request';
type HttpMethod = type HttpMethod =
@ -20,12 +18,7 @@ interface RequestConfig extends AxiosRequestConfig {
method: HttpMethod; method: HttpMethod;
} }
interface RequestLifeCycle { export function useRequest() {
/** 是否自动销毁令牌 */
autoDestroy?: boolean;
}
export function useRequest(options?: RequestLifeCycle) {
const controllers = new Set<AbortController>(); const controllers = new Set<AbortController>();
function request<T>(url: string, config: RequestConfig): Promise<T> { function request<T>(url: string, config: RequestConfig): Promise<T> {
@ -46,13 +39,6 @@ export function useRequest(options?: RequestLifeCycle) {
controllers.clear(); controllers.clear();
} }
onUnmounted(() => {
if (options?.autoDestroy === false) {
return;
}
cancel('The Component has Unmounted!');
});
return { return {
cancel, cancel,
request, request,

4
apps/vben5/packages/types/global.d.ts

@ -11,10 +11,14 @@ export interface VbenAdminProAppConfigRaw {
VITE_GLOB_API_URL: string; VITE_GLOB_API_URL: string;
VITE_GLOB_CLIENT_ID: string; VITE_GLOB_CLIENT_ID: string;
VITE_GLOB_CLIENT_SECRET: string; VITE_GLOB_CLIENT_SECRET: string;
VITE_GLOB_AUTHORITY: string;
VITE_GLOB_AUDIENCE?: string;
} }
export interface ApplicationConfig { export interface ApplicationConfig {
apiURL: string; apiURL: string;
authority: string;
audience?: string;
clientId: string; clientId: string;
clientSecret: string; clientSecret: string;
} }

Loading…
Cancel
Save