登录修改

This commit is contained in:
lxy 2024-08-22 17:57:48 +08:00
parent 48bddab812
commit 5157bc73f3
5 changed files with 187 additions and 213 deletions

View File

@ -22,9 +22,8 @@ export type AspectDict<ED extends EntityDict> = {
) => Promise<string>;
loginByMobile: (
params: {
captcha?: string;
password?: string;
mobile: string;
captcha: string;
disableRegister?: boolean;
env: WebEnv | WechatMpEnv | NativeEnv;
},
@ -34,7 +33,6 @@ export type AspectDict<ED extends EntityDict> = {
params: {
account: string;
password: string;
disableRegister?: boolean;
env: WebEnv | WechatMpEnv | NativeEnv;
},
context: BackendRuntimeContext<ED>

View File

@ -39,7 +39,7 @@ import { mergeUser } from './user';
import { cloneDeep, pick } from 'oak-domain/lib/utils/lodash';
import { BRC } from '../types/RuntimeCxt';
import { SmsConfig } from '../entities/Passport';
import { sendEmail } from '../utils/email';
import { sendEmail } from '../utils/email/index.backend';
import { EmailConfig } from '../oak-app-domain/Passport/Schema';
import { isEmail, isMobile } from 'oak-domain/lib/utils/validator';
@ -584,112 +584,55 @@ async function loadTokenInfo<ED extends EntityDict>(tokenValue: string, context:
export async function loginByMobile<ED extends EntityDict>(
params: {
captcha?: string;
password?: string;
mobile: string;
captcha: string;
disableRegister?: boolean;
env: WebEnv | WechatMpEnv | NativeEnv;
},
context: BRC<ED>
): Promise<string> {
const { mobile, captcha, password, env, disableRegister } = params;
const { mobile, captcha, env, disableRegister } = params;
const loginLogic = async () => {
const systemId = context.getSystemId();
if (captcha) {
const result = await context.select(
'captcha',
{
data: {
id: 1,
expired: 1,
},
filter: {
origin: 'mobile',
content: mobile,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
const result = await context.select(
'captcha',
{
data: {
id: 1,
expired: 1,
},
{ dontCollect: true }
);
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new OakUserException('验证码已经过期');
}
filter: {
origin: 'mobile',
content: mobile,
code: captcha,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
{ dontCollect: true }
);
if (result.length > 0) {
const [captchaRow] = result;
if (captchaRow.expired) {
throw new OakUserException('验证码已经过期');
}
// 到这里说明验证码已经通过
return await setupMobile<ED>(mobile, env, context);
} else {
throw new OakUserException('验证码无效');
}
// 到这里说明验证码已经通过
return await setupMobile<ED>(mobile, env, context);
} else {
assert(password);
const result = await context.select(
'mobile',
{
data: {
id: 1,
userId: 1,
ableState: 1,
},
filter: {
mobile: mobile,
user: {
$or: [
{
password,
},
{
passwordSha1: encryptPasswordSha1(password),
},
],
},
},
},
{
dontCollect: true,
}
);
switch (result.length) {
case 0: {
throw new OakUserException('用户名与密码不匹配');
}
case 1: {
const [mobileRow] = result;
const { ableState, userId } = mobileRow;
if (ableState === 'disabled') {
// 虽然密码和手机号匹配,但手机号已经禁用了,在可能的情况下提醒用户使用其它方法登录
const exception = await tryMakeChangeLoginWay<ED>(
userId as string,
context
);
if (exception) {
throw exception;
}
}
return await setupMobile<ED>(mobile, env, context);
}
default: {
throw new Error(
`手机号和密码匹配出现雷同mobile id是[${result
.map((ele) => ele.id)
.join(',')}], mobile是${mobile}`
);
}
}
throw new OakUserException('验证码无效');
}
};
const closeRootMode = context.openRootMode();
if (disableRegister) {
const [existMobile] = await context.select(
@ -722,12 +665,11 @@ export async function loginByAccount<ED extends EntityDict>(
params: {
account: string;
password: string;
disableRegister?: boolean;
env: WebEnv | WechatMpEnv | NativeEnv;
},
context: BRC<ED>
): Promise<string> {
const { account, password, env, disableRegister } = params;
const { account, password, env, } = params;
const loginLogic = async () => {
const systemId = context.getSystemId();
@ -752,6 +694,14 @@ export async function loginByAccount<ED extends EntityDict>(
email: 1,
ableState: 1,
}
},
loginName$user: {
$entity: 'loginName',
data: {
id: 1,
name: 1,
ableState: 1,
}
}
},
filter: {
@ -768,6 +718,11 @@ export async function loginByAccount<ED extends EntityDict>(
email: account,
}
},
{
loginName$user: {
name: account,
}
}
]
},
{
@ -790,11 +745,11 @@ export async function loginByAccount<ED extends EntityDict>(
);
switch (result.length) {
case 0: {
throw new OakUserException('用户名与密码不匹配');
throw new OakUserException('账号与密码不匹配');
}
case 1: {
const [userRow] = result;
const { mobile$user, email$user, id: userId, } = userRow;
const { mobile$user, email$user, loginName$user, id: userId, } = userRow;
if (mobile$user && mobile$user.length > 0) {
const ableState = mobile$user[0].ableState;
if (ableState === 'disabled') {
@ -821,79 +776,28 @@ export async function loginByAccount<ED extends EntityDict>(
}
}
return await setupEmail<ED>(account, env, context);
} else if (loginName$user && loginName$user.length > 0) {
const ableState = loginName$user[0].ableState;
if (ableState === 'disabled') {
// 虽然密码和邮箱匹配,但邮箱已经禁用了,在可能的情况下提醒用户使用其它方法登录
const exception = await tryMakeChangeLoginWay<ED>(
userId as string,
context
);
if (exception) {
throw exception;
}
}
return await setupLoginName<ED>(account, env, context);
}
return ''
}
default: {
throw new Error(
// `手机号和密码匹配出现雷同mobile id是[${result
// .map((ele) => ele.id)
// .join(',')}], mobile是${mobile}`
);
throw new Error('不支持的登录方式');
}
}
};
const closeRootMode = context.openRootMode();
if (disableRegister) {
if (isMobile(account)) {
const [existMobile] = await context.select(
'mobile',
{
data: {
id: 1,
mobile: 1,
},
filter: {
mobile: account!,
ableState: 'enabled',
},
},
{ dontCollect: true }
);
if (!existMobile) {
closeRootMode();
throw new OakUserException('账号不存在');
}
} else if (isEmail(account)) {
const [existEmail] = await context.select(
'email',
{
data: {
id: 1,
email: 1,
},
filter: {
email: account!,
ableState: 'enabled',
},
},
{ dontCollect: true }
);
if (!existEmail) {
closeRootMode();
throw new OakUserException('账号不存在');
}
} else {
// const [existMobile] = await context.select(
// 'mobile',
// {
// data: {
// id: 1,
// mobile: 1,
// },
// filter: {
// mobile: mobile!,
// ableState: 'enabled',
// },
// },
// { dontCollect: true }
// );
// if (!existMobile) {
// closeRootMode();
// throw new OakUserException('账号不存在');
// }
}
}
const tokenValue = await loginLogic();
await loadTokenInfo<ED>(tokenValue, context);
closeRootMode();
@ -979,6 +883,70 @@ export async function loginByEmail<ED extends EntityDict>(
return tokenValue;
}
async function setupLoginName<ED extends EntityDict>(name: string, env: WebEnv | WechatMpEnv | NativeEnv, context: BRC<ED>) {
const result2 = await context.select(
'loginName',
{
data: {
id: 1,
name: 1,
userId: 1,
ableState: 1,
user: {
id: 1,
userState: 1,
refId: 1,
ref: {
id: 1,
userState: 1,
refId: 1,
},
wechatUser$user: {
$entity: 'wechatUser',
data: {
id: 1,
},
},
userSystem$user: {
$entity: 'userSystem',
data: {
id: 1,
systemId: 1,
},
},
},
},
filter: {
name,
ableState: 'enabled',
},
},
{ dontCollect: true }
);
assert(result2.length === 1);
const [loginNameRow] = result2;
const { user } = loginNameRow;
const { userState, ref } = user!;
if (userState === 'merged') {
return await setUpTokenAndUser<ED>(
env,
context,
'loginName',
loginNameRow.id,
undefined,
ref as Partial<ED['user']['Schema']>
);
}
return await setUpTokenAndUser<ED>(
env,
context,
'loginName',
loginNameRow.id,
undefined,
user as Partial<ED['user']['Schema']>
);
}
async function setupEmail<ED extends EntityDict>(email: string, env: WebEnv | WechatMpEnv | NativeEnv, context: BRC<ED>) {
const result2 = await context.select(
'email',
@ -2088,6 +2056,18 @@ export async function sendCaptchaByEmail<ED extends EntityDict>(
const duration = config.codeDuration || 5;
const digit = config.digit || 4;
let emailOptions = {
host: config.host,
port: config.port,
account: config.account,
password: config.password,
subject: config.subject,
from: config.name ? `"${config.name}" <${config.account}>` : config.account,
to: email,
text: config.text,
html: config.html,
}
const now = Date.now();
const closeRootMode = context.openRootMode();
if (process.env.NODE_ENV !== 'development') {
@ -2153,26 +2133,24 @@ export async function sendCaptchaByEmail<ED extends EntityDict>(
);
if (captcha) {
const code = captcha.code!;
if (process.env.NODE_ENV === 'development') {
closeRootMode();
return `验证码[${code}]已创建`;
} else if (now - (captcha.$$createAt$$! as number) < 60000) {
// if (process.env.NODE_ENV === 'development') {
// closeRootMode();
// return `验证码[${code}]已创建`;
// } else
if (now - (captcha.$$createAt$$! as number) < 60000) {
closeRootMode();
throw new OakUserException('您的操作太迅捷啦,请稍等再点吧');
} else {
assert(config.account, '必须设置邮箱');
// todo 再次发送
const text = config.text?.replace('${duration}', duration.toString() + '分钟').replace('${code}', code);
const html = config.html?.replace('${duration}', duration.toString() + '分钟').replace('${code}', code);
emailOptions.text = text;
emailOptions.html = html;
const result = await sendEmail(
config.host,
config.port,
config.account,
config.password,
config.subject,
email,
config.name,
config.text,
config.html,
{ code, duration: duration.toString() },
{
...emailOptions,
}
);
closeRootMode();
if (result.success) {
@ -2209,30 +2187,27 @@ export async function sendCaptchaByEmail<ED extends EntityDict>(
}
);
if (process.env.NODE_ENV === 'development') {
closeRootMode();
return `验证码[${code}]已创建`;
} else {
assert(config.account, '必须设置邮箱');
//发送邮件
const result = await sendEmail(
config.host,
config.port,
config.account,
config.password,
config.subject,
email,
config.name,
config.text,
config.html,
{ code, duration: duration.toString() },
);
closeRootMode();
if (result.success) {
return '验证码已发送';
// if (process.env.NODE_ENV === 'development') {
// closeRootMode();
// return `验证码[${code}]已创建`;
// } else {
assert(config.account, '必须设置邮箱');
//发送邮件
const text = config.text?.replace('${duration}', duration.toString() + '分钟').replace('${code}', code);
const html = config.html?.replace('${duration}', duration.toString() + '分钟').replace('${code}', code);
emailOptions.text = text;
emailOptions.html = html;
const result = await sendEmail(
{
...emailOptions,
}
return '验证码发送失败';
);
closeRootMode();
if (result.success) {
return '验证码已发送';
}
return '验证码发送失败';
// }
}
}

View File

@ -90,11 +90,10 @@ export default OakComponent({
},
async loginByMobile() {
const { eventLoggedIn, callback } = this.props;
const { mobile, password, captcha } = this.state;
const { mobile,captcha } = this.state;
try {
await this.features.token.loginByMobile(
mobile,
password,
captcha
);
if (typeof callback === 'function') {

View File

@ -18,6 +18,7 @@ export default OakComponent({
password: '',
validMobile: false,
vaildEmail: false,
vaildAccount: false,
validPassword: false,
allowSubmit: false,
},
@ -34,16 +35,16 @@ export default OakComponent({
lifetimes: {
},
listeners: {
'validMobile,vaildEmail,validPassword'(prev, next) {
'vaildAccount,validPassword'(prev, next) {
const { allowSubmit } = this.state;
if (allowSubmit) {
if (!((next.validMobile || next.vaildEmail) && next.validPassword)) {
if (!(next.vaildAccount && next.validPassword)) {
this.setState({
allowSubmit: false,
})
}
} else {
if ((next.validMobile || next.vaildEmail) && next.validPassword) {
if (next.vaildAccount && next.validPassword) {
this.setState({
allowSubmit: true,
})
@ -52,7 +53,7 @@ export default OakComponent({
}
},
methods: {
async loginByPassword() {
async loginByAccount() {
const { url, callback } = this.props;
const { account, password } = this.state;
try {
@ -90,12 +91,14 @@ export default OakComponent({
const { allowSms, allowEmail } = this.props;
switch (type) {
case 'account':
const validMobile = allowSms && !!isMobile(value);
const vaildEmail = allowEmail && !!isEmail(value);
// const validMobile = allowSms && !!isMobile(value);
// const vaildEmail = allowEmail && !!isEmail(value);
const vaildAccount = !!(value && value.trim() && value.trim() !== '');
this.setState({
account: value,
validMobile,
vaildEmail,
// validMobile,
// vaildEmail,
vaildAccount,
})
break;
case 'password':

View File

@ -114,7 +114,6 @@ export default OakComponent({
});
await this.features.token.loginByMobile(
mobile,
undefined,
captcha
);
this.setState({