Browse Source

feat(vben5): Realize mobile phone number login

- 新增手机号码登录api
- 新增发送手机登录验证码api
- 新增发送手机重置密码验证码api
pull/1219/head
colin 8 months ago
parent
commit
f77c96cdc2
  1. 31
      apps/vben5/apps/app-antd/src/store/auth.ts
  2. 42
      apps/vben5/apps/app-antd/src/views/_core/authentication/code-login.vue
  3. 1
      apps/vben5/packages/@abp/account/src/api/index.ts
  4. 28
      apps/vben5/packages/@abp/account/src/api/useAccountApi.ts
  5. 46
      apps/vben5/packages/@abp/account/src/api/usePhoneLoginApi.ts
  6. 2
      apps/vben5/packages/@abp/account/src/api/useQrCodeLoginApi.ts
  7. 12
      apps/vben5/packages/@abp/account/src/types/account.ts
  8. 8
      apps/vben5/packages/@abp/account/src/types/token.ts

31
apps/vben5/apps/app-antd/src/store/auth.ts

@ -2,13 +2,14 @@ import type { TokenResult } from '@abp/account';
import type { Recordable, UserInfo } from '@vben/types';
import { ref } from 'vue';
import { ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
import {
usePhoneLoginApi,
useProfileApi,
useQrCodeLoginApi,
useTokenApi,
@ -25,6 +26,7 @@ export const useAuthStore = defineStore('auth', () => {
const { publish } = useEventBus();
const { loginApi } = useTokenApi();
const { loginApi: qrcodeLoginApi } = useQrCodeLoginApi();
const { loginApi: phoneLoginApi } = usePhoneLoginApi();
const { getUserInfoApi } = useUserInfoApi();
const { getConfigApi } = useAbpConfigApi();
const { getPictureApi } = useProfileApi();
@ -35,6 +37,17 @@ export const useAuthStore = defineStore('auth', () => {
const loginLoading = ref(false);
watch(
() => accessStore.accessToken,
(accessToken) => {
if (accessToken && !loginLoading.value) {
loginLoading.value = true;
fetchUserInfo();
loginLoading.value = false;
}
},
);
async function qrcodeLogin(
key: string,
tenantId?: string,
@ -49,6 +62,20 @@ export const useAuthStore = defineStore('auth', () => {
}
}
async function phoneLogin(
phoneNumber: string,
code: string,
onSuccess?: () => Promise<void> | void,
) {
try {
loginLoading.value = true;
const result = await phoneLoginApi({ phoneNumber, code });
return await _loginSuccess(result, onSuccess);
} finally {
loginLoading.value = false;
}
}
/**
*
* Asynchronously handle the login process
@ -126,7 +153,6 @@ export const useAuthStore = defineStore('auth', () => {
) {
// 异步处理用户登录操作并获取 accessToken
let userInfo: null | UserInfo = null;
loginLoading.value = true;
const { accessToken, tokenType, refreshToken } = loginResult;
// 如果成功获取到 accessToken
if (accessToken) {
@ -172,6 +198,7 @@ export const useAuthStore = defineStore('auth', () => {
return {
$reset,
authLogin,
phoneLogin,
qrcodeLogin,
fetchUserInfo,
loginLoading,

42
apps/vben5/apps/app-antd/src/views/_core/authentication/code-login.vue

@ -1,29 +1,42 @@
<script lang="ts" setup>
import type { VbenFormSchema } from '@vben/common-ui';
import type { ExtendedFormApi, VbenFormSchema } from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import { computed, ref } from 'vue';
import { computed, ref, useTemplateRef } from 'vue';
import { AuthenticationCodeLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useAccountApi } from '@abp/account';
import { isPhone } from '@abp/core';
import { useAuthStore } from '#/store/auth';
interface CodeLoginExpose {
getFormApi(): ExtendedFormApi;
}
defineOptions({ name: 'CodeLogin' });
const authStore = useAuthStore();
const { sendPhoneSigninCodeApi } = useAccountApi();
const loading = ref(false);
const codeLogin = useTemplateRef<CodeLoginExpose>('codeLogin');
const formSchema = computed((): VbenFormSchema[] => {
return [
{
component: 'VbenInput',
component: 'Input',
componentProps: {
placeholder: $t('authentication.mobile'),
placeholder: $t('AbpAccount.DisplayName:PhoneNumber'),
},
fieldName: 'phoneNumber',
label: $t('authentication.mobile'),
label: $t('AbpAccount.DisplayName:PhoneNumber'),
rules: z
.string()
.min(1, { message: $t('authentication.mobileTip') })
.refine((v) => /^\d{11}$/.test(v), {
.refine((v) => isPhone(v), {
message: $t('authentication.mobileErrortip'),
}),
},
@ -37,6 +50,7 @@ const formSchema = computed((): VbenFormSchema[] => {
: $t('authentication.sendCode');
return text;
},
handleSendCode: onSendCode,
placeholder: $t('authentication.code'),
},
fieldName: 'code',
@ -45,19 +59,31 @@ const formSchema = computed((): VbenFormSchema[] => {
},
];
});
async function onSendCode() {
const formApi = codeLogin.value?.getFormApi();
const input = await formApi?.getValues();
await sendPhoneSigninCodeApi({
phoneNumber: input!.phoneNumber,
});
}
/**
* 异步处理登录操作
* Asynchronously handle the login process
* @param values 登录表单数据
*/
async function handleLogin(values: Recordable<any>) {
// eslint-disable-next-line no-console
console.log(values);
try {
loading.value = true;
await authStore.phoneLogin(values.phoneNumber, values.code);
} finally {
loading.value = false;
}
}
</script>
<template>
<AuthenticationCodeLogin
ref="codeLogin"
:form-schema="formSchema"
:loading="loading"
@submit="handleLogin"

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

@ -1,5 +1,6 @@
export { useAccountApi } from './useAccountApi';
export { useMySessionApi } from './useMySessionApi';
export { usePhoneLoginApi } from './usePhoneLoginApi';
export { useProfileApi } from './useProfileApi';
export { useQrCodeLoginApi } from './useQrCodeLoginApi';
export { useTokenApi } from './useTokenApi';

28
apps/vben5/packages/@abp/account/src/api/useAccountApi.ts

@ -2,7 +2,9 @@ import type { ListResultDto } from '@abp/core';
import type {
GetTwoFactorProvidersInput,
PhoneResetPasswordDto,
SendEmailSigninCodeDto,
SendPhoneResetPasswordCodeDto,
SendPhoneSigninCodeDto,
TwoFactorProvider,
} from '../types/account';
@ -54,10 +56,36 @@ export function useAccountApi() {
});
}
/**
*
* @param input
*/
function sendPhoneResetPasswordCodeApi(
input: SendPhoneResetPasswordCodeDto,
): Promise<void> {
return request('/api/account/phone/send-password-reset-code', {
data: input,
method: 'POST',
});
}
/**
*
* @param input
*/
function resetPasswordApi(input: PhoneResetPasswordDto): Promise<void> {
return request('/api/account/phone/reset-password', {
data: input,
method: 'PUT',
});
}
return {
cancel,
getTwoFactorProvidersApi,
resetPasswordApi,
sendEmailSigninCodeApi,
sendPhoneResetPasswordCodeApi,
sendPhoneSigninCodeApi,
};
}

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

@ -0,0 +1,46 @@
import type { OAuthTokenResult, PhoneNumberTokenRequest } from '../types/token';
import { useAppConfig } from '@vben/hooks';
import { useRequest } from '@abp/request';
export function usePhoneLoginApi() {
const { cancel, request } = useRequest();
/**
*
* @param input
* @returns token
*/
async function loginApi(input: PhoneNumberTokenRequest) {
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: 'phone_verify',
phone_number: input.phoneNumber,
phone_verify_code: input.code,
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,
};
}

2
apps/vben5/packages/@abp/account/src/api/useQrCodeLoginApi.ts

@ -34,7 +34,7 @@ export function useQrCodeLoginApi() {
/**
*
* @param key Key
* @param input
* @returns token
*/
async function loginApi(input: QrCodeTokenRequest) {

12
apps/vben5/packages/@abp/account/src/types/account.ts

@ -12,11 +12,23 @@ interface SendPhoneSigninCodeDto {
phoneNumber: string;
}
interface SendPhoneResetPasswordCodeDto {
phoneNumber: string;
}
interface PhoneResetPasswordDto {
code: string;
newPassword: string;
phoneNumber: string;
}
type TwoFactorProvider = NameValue<string>;
export type {
GetTwoFactorProvidersInput,
PhoneResetPasswordDto,
SendEmailSigninCodeDto,
SendPhoneResetPasswordCodeDto,
SendPhoneSigninCodeDto,
TwoFactorProvider,
};

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

@ -14,6 +14,13 @@ interface PasswordTokenRequest extends TokenRequest {
/** 用户名 */
userName: string;
}
/** 手机号授权请求数据模型 */
interface PhoneNumberTokenRequest {
/** 验证码 */
code: string;
/** 手机号 */
phoneNumber: string;
}
/** 扫码登录授权请求数据模型 */
interface QrCodeTokenRequest {
/** 二维码Key */
@ -80,6 +87,7 @@ export type {
OAuthTokenResult,
PasswordTokenRequest,
PasswordTokenRequestModel,
PhoneNumberTokenRequest,
QrCodeTokenRequest,
ShouldChangePasswordError,
TokenRequest,

Loading…
Cancel
Save