Compare commits

...

2 Commits

Author SHA1 Message Date
lxy 67341a64df fix: i18n 2025-11-20 10:39:03 +08:00
lxy b839318c5c refactor: 调整密码登录异常顺序 2025-11-20 10:38:05 +08:00
7 changed files with 181 additions and 251 deletions

View File

@ -593,8 +593,35 @@ export async function loginByAccount(params, context) {
assert(password); assert(password);
assert(account); assert(account);
const accountType = isEmail(account) ? 'email' : (isMobile(account) ? 'mobile' : 'loginName'); const accountType = isEmail(account) ? 'email' : (isMobile(account) ? 'mobile' : 'loginName');
const applicationPassports = await context.select('applicationPassport', {
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
}, {
dontCollect: true,
});
const allowEmail = !!applicationPassports.find((ele) => ele.passport?.type === 'email');
const allowSms = !!applicationPassports.find((ele) => ele.passport?.type === 'sms');
if (accountType === 'email') { if (accountType === 'email') {
const { config, emailConfig } = await getAndCheckPassportByEmail(context, account); const { config, emailConfig } = await getAndCheckPassportByEmail(context, account);
if (!allowEmail) {
throw new OakUserException('暂不支持邮箱登录');
}
const existEmail = await context.select('email', { const existEmail = await context.select('email', {
data: { data: {
id: 1, id: 1,
@ -641,51 +668,23 @@ export async function loginByAccount(params, context) {
throw new OakUserException('error::user.passwordUnmath'); throw new OakUserException('error::user.passwordUnmath');
} }
case 1: { case 1: {
const applicationPassports = await context.select('applicationPassport', {
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
}, {
dontCollect: true,
});
const allowEmail = !!applicationPassports.find((ele) => ele.passport?.type === 'email');
const [userRow] = result; const [userRow] = result;
const { email$user, id: userId, } = userRow; const { email$user, id: userId, } = userRow;
needUpdatePassword = !(userRow.password || userRow.passwordSha1); needUpdatePassword = !(userRow.password || userRow.passwordSha1);
if (allowEmail) { const email = email$user?.find(ele => ele.email.toLowerCase() === account.toLowerCase());
const email = email$user?.find(ele => ele.email.toLowerCase() === account.toLowerCase()); if (email) {
if (email) { const ableState = email.ableState;
const ableState = email.ableState; if (ableState === 'disabled') {
if (ableState === 'disabled') { // 虽然密码和邮箱匹配,但邮箱已经禁用了,在可能的情况下提醒用户使用其它方法登录
// 虽然密码和邮箱匹配,但邮箱已经禁用了,在可能的情况下提醒用户使用其它方法登录 const exception = await tryMakeChangeLoginWay(userId, context);
const exception = await tryMakeChangeLoginWay(userId, context); if (exception) {
if (exception) { throw exception;
throw exception;
}
} }
return await setupEmail(account, env, context);
}
else {
throw new OakUserException('error::user.emailUnexists');
} }
return await setupEmail(account, env, context);
} }
else { else {
throw new OakUserException('error::user.loginWayDisabled'); throw new OakUserException('error::user.emailUnexists');
} }
} }
default: { default: {
@ -694,6 +693,9 @@ export async function loginByAccount(params, context) {
} }
} }
else if (accountType === 'mobile') { else if (accountType === 'mobile') {
if (!allowSms) {
throw new OakUserException('暂不支持手机号登录');
}
const existMobile = await context.select('mobile', { const existMobile = await context.select('mobile', {
data: { data: {
id: 1, id: 1,
@ -740,55 +742,27 @@ export async function loginByAccount(params, context) {
throw new OakUserException('手机号与密码不匹配'); throw new OakUserException('手机号与密码不匹配');
} }
case 1: { case 1: {
const applicationPassports = await context.select('applicationPassport', {
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
}, {
dontCollect: true,
});
const [userRow] = result; const [userRow] = result;
const { mobile$user, id: userId, } = userRow; const { mobile$user, id: userId, } = userRow;
needUpdatePassword = !(userRow.password || userRow.passwordSha1); needUpdatePassword = !(userRow.password || userRow.passwordSha1);
const allowSms = !!applicationPassports.find((ele) => ele.passport?.type === 'sms'); const mobile = mobile$user?.find(ele => ele.mobile === account);
if (allowSms) { if (mobile) {
const mobile = mobile$user?.find(ele => ele.mobile === account); const ableState = mobile.ableState;
if (mobile) { if (ableState === 'disabled') {
const ableState = mobile.ableState; // 虽然密码和手机号匹配,但手机号已经禁用了,在可能的情况下提醒用户使用其它方法登录
if (ableState === 'disabled') { const exception = await tryMakeChangeLoginWay(userId, context);
// 虽然密码和手机号匹配,但手机号已经禁用了,在可能的情况下提醒用户使用其它方法登录 if (exception) {
const exception = await tryMakeChangeLoginWay(userId, context); throw exception;
if (exception) {
throw exception;
}
} }
return await setupMobile(account, env, context);
}
else {
throw new OakUserException('手机号未注册');
} }
return await setupMobile(account, env, context);
} }
else { else {
throw new OakUserException('暂不支持手机号登录'); throw new OakUserException('手机号未注册');
} }
} }
default: { default: {
throw new OakUserException('不支持的登录方式'); throw new OakUserException('error::user.loginWayDisabled');
} }
} }
} }
@ -859,7 +833,7 @@ export async function loginByAccount(params, context) {
} }
} }
default: { default: {
throw new OakUserException('不支持的登录方式'); throw new OakUserException('error::user.loginWayDisabled');
} }
} }
} }

View File

@ -35,6 +35,9 @@ export default OakComponent({
}, },
passport: { passport: {
systemId, systemId,
type: {
$ne: 'password'
}
}, },
}; };
} }
@ -166,6 +169,9 @@ export default OakComponent({
filter: { filter: {
systemId, systemId,
enabled: true, enabled: true,
type: {
$ne: 'password',
}
}, },
sorter: [{ sorter: [{
$attr: { $attr: {

View File

@ -14,7 +14,7 @@ export default function Render(props) {
}} className={Style['loginbox-input']}/> }} className={Style['loginbox-input']}/>
</Form.Item> </Form.Item>
<Form.Item name="captcha"> <Form.Item name="captcha">
<Input allowClear value={captcha} size="large" maxLength={digit} placeholder={t('placeholder.Captcha')} onChange={(e) => { <Input allowClear value={captcha} size="large" maxLength={digit} placeholder={t('placeholder.Captcha', { digit })} onChange={(e) => {
inputChange('captcha', e.target.value); inputChange('captcha', e.target.value);
}} className={Style['loginbox-input']} suffix={<Button size="small" type="link" disabled={!!disabled || !validEmail || counter > 0} onClick={() => sendCaptcha()}> }} className={Style['loginbox-input']} suffix={<Button size="small" type="link" disabled={!!disabled || !validEmail || counter > 0} onClick={() => sendCaptcha()}>
{counter > 0 {counter > 0

View File

@ -619,8 +619,35 @@ async function loginByAccount(params, context) {
(0, assert_1.assert)(password); (0, assert_1.assert)(password);
(0, assert_1.assert)(account); (0, assert_1.assert)(account);
const accountType = (0, validator_1.isEmail)(account) ? 'email' : ((0, validator_1.isMobile)(account) ? 'mobile' : 'loginName'); const accountType = (0, validator_1.isEmail)(account) ? 'email' : ((0, validator_1.isMobile)(account) ? 'mobile' : 'loginName');
const applicationPassports = await context.select('applicationPassport', {
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
}, {
dontCollect: true,
});
const allowEmail = !!applicationPassports.find((ele) => ele.passport?.type === 'email');
const allowSms = !!applicationPassports.find((ele) => ele.passport?.type === 'sms');
if (accountType === 'email') { if (accountType === 'email') {
const { config, emailConfig } = await (0, passport_1.getAndCheckPassportByEmail)(context, account); const { config, emailConfig } = await (0, passport_1.getAndCheckPassportByEmail)(context, account);
if (!allowEmail) {
throw new types_1.OakUserException('暂不支持邮箱登录');
}
const existEmail = await context.select('email', { const existEmail = await context.select('email', {
data: { data: {
id: 1, id: 1,
@ -667,51 +694,23 @@ async function loginByAccount(params, context) {
throw new types_1.OakUserException('error::user.passwordUnmath'); throw new types_1.OakUserException('error::user.passwordUnmath');
} }
case 1: { case 1: {
const applicationPassports = await context.select('applicationPassport', {
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
}, {
dontCollect: true,
});
const allowEmail = !!applicationPassports.find((ele) => ele.passport?.type === 'email');
const [userRow] = result; const [userRow] = result;
const { email$user, id: userId, } = userRow; const { email$user, id: userId, } = userRow;
needUpdatePassword = !(userRow.password || userRow.passwordSha1); needUpdatePassword = !(userRow.password || userRow.passwordSha1);
if (allowEmail) { const email = email$user?.find(ele => ele.email.toLowerCase() === account.toLowerCase());
const email = email$user?.find(ele => ele.email.toLowerCase() === account.toLowerCase()); if (email) {
if (email) { const ableState = email.ableState;
const ableState = email.ableState; if (ableState === 'disabled') {
if (ableState === 'disabled') { // 虽然密码和邮箱匹配,但邮箱已经禁用了,在可能的情况下提醒用户使用其它方法登录
// 虽然密码和邮箱匹配,但邮箱已经禁用了,在可能的情况下提醒用户使用其它方法登录 const exception = await tryMakeChangeLoginWay(userId, context);
const exception = await tryMakeChangeLoginWay(userId, context); if (exception) {
if (exception) { throw exception;
throw exception;
}
} }
return await setupEmail(account, env, context);
}
else {
throw new types_1.OakUserException('error::user.emailUnexists');
} }
return await setupEmail(account, env, context);
} }
else { else {
throw new types_1.OakUserException('error::user.loginWayDisabled'); throw new types_1.OakUserException('error::user.emailUnexists');
} }
} }
default: { default: {
@ -720,6 +719,9 @@ async function loginByAccount(params, context) {
} }
} }
else if (accountType === 'mobile') { else if (accountType === 'mobile') {
if (!allowSms) {
throw new types_1.OakUserException('暂不支持手机号登录');
}
const existMobile = await context.select('mobile', { const existMobile = await context.select('mobile', {
data: { data: {
id: 1, id: 1,
@ -766,55 +768,27 @@ async function loginByAccount(params, context) {
throw new types_1.OakUserException('手机号与密码不匹配'); throw new types_1.OakUserException('手机号与密码不匹配');
} }
case 1: { case 1: {
const applicationPassports = await context.select('applicationPassport', {
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
}, {
dontCollect: true,
});
const [userRow] = result; const [userRow] = result;
const { mobile$user, id: userId, } = userRow; const { mobile$user, id: userId, } = userRow;
needUpdatePassword = !(userRow.password || userRow.passwordSha1); needUpdatePassword = !(userRow.password || userRow.passwordSha1);
const allowSms = !!applicationPassports.find((ele) => ele.passport?.type === 'sms'); const mobile = mobile$user?.find(ele => ele.mobile === account);
if (allowSms) { if (mobile) {
const mobile = mobile$user?.find(ele => ele.mobile === account); const ableState = mobile.ableState;
if (mobile) { if (ableState === 'disabled') {
const ableState = mobile.ableState; // 虽然密码和手机号匹配,但手机号已经禁用了,在可能的情况下提醒用户使用其它方法登录
if (ableState === 'disabled') { const exception = await tryMakeChangeLoginWay(userId, context);
// 虽然密码和手机号匹配,但手机号已经禁用了,在可能的情况下提醒用户使用其它方法登录 if (exception) {
const exception = await tryMakeChangeLoginWay(userId, context); throw exception;
if (exception) {
throw exception;
}
} }
return await setupMobile(account, env, context);
}
else {
throw new types_1.OakUserException('手机号未注册');
} }
return await setupMobile(account, env, context);
} }
else { else {
throw new types_1.OakUserException('暂不支持手机号登录'); throw new types_1.OakUserException('手机号未注册');
} }
} }
default: { default: {
throw new types_1.OakUserException('不支持的登录方式'); throw new types_1.OakUserException('error::user.loginWayDisabled');
} }
} }
} }
@ -885,7 +859,7 @@ async function loginByAccount(params, context) {
} }
} }
default: { default: {
throw new types_1.OakUserException('不支持的登录方式'); throw new types_1.OakUserException('error::user.loginWayDisabled');
} }
} }
} }

View File

@ -798,10 +798,40 @@ export async function loginByAccount<ED extends EntityDict>(
assert(password); assert(password);
assert(account); assert(account);
const accountType = isEmail(account) ? 'email' : (isMobile(account) ? 'mobile' : 'loginName'); const accountType = isEmail(account) ? 'email' : (isMobile(account) ? 'mobile' : 'loginName');
const applicationPassports = await context.select(
'applicationPassport',
{
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
},
{
dontCollect: true,
}
);
const allowEmail = !!applicationPassports.find((ele) => ele.passport?.type === 'email');
const allowSms = !!applicationPassports.find((ele) => ele.passport?.type === 'sms');
if (accountType === 'email') { if (accountType === 'email') {
const { config, emailConfig } = await getAndCheckPassportByEmail(context, account); const { config, emailConfig } = await getAndCheckPassportByEmail(context, account);
if (!allowEmail) {
throw new OakUserException('暂不支持邮箱登录');
}
const existEmail = await context.select( const existEmail = await context.select(
'email', 'email',
{ {
@ -856,56 +886,25 @@ export async function loginByAccount<ED extends EntityDict>(
throw new OakUserException('error::user.passwordUnmath'); throw new OakUserException('error::user.passwordUnmath');
} }
case 1: { case 1: {
const applicationPassports = await context.select(
'applicationPassport',
{
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
},
{
dontCollect: true,
}
);
const allowEmail = !!applicationPassports.find((ele) => ele.passport?.type === 'email');
const [userRow] = result; const [userRow] = result;
const { email$user, id: userId, } = userRow; const { email$user, id: userId, } = userRow;
needUpdatePassword = !(userRow.password || userRow.passwordSha1); needUpdatePassword = !(userRow.password || userRow.passwordSha1);
if (allowEmail) { const email = email$user?.find(ele => ele.email.toLowerCase() === account.toLowerCase());
const email = email$user?.find(ele => ele.email.toLowerCase() === account.toLowerCase()); if (email) {
if (email) { const ableState = email.ableState;
const ableState = email.ableState; if (ableState === 'disabled') {
if (ableState === 'disabled') { // 虽然密码和邮箱匹配,但邮箱已经禁用了,在可能的情况下提醒用户使用其它方法登录
// 虽然密码和邮箱匹配,但邮箱已经禁用了,在可能的情况下提醒用户使用其它方法登录 const exception = await tryMakeChangeLoginWay<ED>(
const exception = await tryMakeChangeLoginWay<ED>( userId as string,
userId as string, context
context );
); if (exception) {
if (exception) { throw exception;
throw exception;
}
} }
return await setupEmail<ED>(account, env, context);
} else {
throw new OakUserException('error::user.emailUnexists');
} }
return await setupEmail<ED>(account, env, context);
} else { } else {
throw new OakUserException('error::user.loginWayDisabled'); throw new OakUserException('error::user.emailUnexists');
} }
} }
default: { default: {
@ -913,6 +912,9 @@ export async function loginByAccount<ED extends EntityDict>(
} }
} }
} else if (accountType === 'mobile') { } else if (accountType === 'mobile') {
if (!allowSms) {
throw new OakUserException('暂不支持手机号登录');
}
const existMobile = await context.select( const existMobile = await context.select(
'mobile', 'mobile',
{ {
@ -968,61 +970,29 @@ export async function loginByAccount<ED extends EntityDict>(
throw new OakUserException('手机号与密码不匹配'); throw new OakUserException('手机号与密码不匹配');
} }
case 1: { case 1: {
const applicationPassports = await context.select(
'applicationPassport',
{
data: {
id: 1,
applicationId: 1,
passportId: 1,
passport: {
id: 1,
type: 1,
systemId: 1,
},
allowPwd: 1,
},
filter: {
passport: {
systemId,
},
applicationId,
allowPwd: true,
}
},
{
dontCollect: true,
}
);
const [userRow] = result; const [userRow] = result;
const { mobile$user, id: userId, } = userRow; const { mobile$user, id: userId, } = userRow;
needUpdatePassword = !(userRow.password || userRow.passwordSha1); needUpdatePassword = !(userRow.password || userRow.passwordSha1);
const allowSms = !!applicationPassports.find((ele) => ele.passport?.type === 'sms'); const mobile = mobile$user?.find(ele => ele.mobile === account);
if (mobile) {
if (allowSms) { const ableState = mobile.ableState;
const mobile = mobile$user?.find(ele => ele.mobile === account); if (ableState === 'disabled') {
if (mobile) { // 虽然密码和手机号匹配,但手机号已经禁用了,在可能的情况下提醒用户使用其它方法登录
const ableState = mobile.ableState; const exception = await tryMakeChangeLoginWay<ED>(
if (ableState === 'disabled') { userId as string,
// 虽然密码和手机号匹配,但手机号已经禁用了,在可能的情况下提醒用户使用其它方法登录 context
const exception = await tryMakeChangeLoginWay<ED>( );
userId as string, if (exception) {
context throw exception;
);
if (exception) {
throw exception;
}
} }
return await setupMobile<ED>(account, env, context);
} else {
throw new OakUserException('手机号未注册');
} }
return await setupMobile<ED>(account, env, context);
} else { } else {
throw new OakUserException('暂不支持手机号登录'); throw new OakUserException('手机号未注册');
} }
} }
default: { default: {
throw new OakUserException('不支持的登录方式'); throw new OakUserException('error::user.loginWayDisabled');
} }
} }
} else { } else {
@ -1103,7 +1073,7 @@ export async function loginByAccount<ED extends EntityDict>(
} }
} }
default: { default: {
throw new OakUserException('不支持的登录方式'); throw new OakUserException('error::user.loginWayDisabled');
} }
} }
} }

View File

@ -74,6 +74,9 @@ export default OakComponent({
}, },
passport: { passport: {
systemId, systemId,
type: {
$ne: 'password'
}
}, },
} }
} }
@ -206,6 +209,9 @@ export default OakComponent({
filter: { filter: {
systemId, systemId,
enabled: true, enabled: true,
type: {
$ne: 'password',
}
}, },
sorter: [{ sorter: [{
$attr: { $attr: {

View File

@ -65,7 +65,7 @@ export default function Render(
value={captcha} value={captcha}
size="large" size="large"
maxLength={digit} maxLength={digit}
placeholder={t('placeholder.Captcha')} placeholder={t('placeholder.Captcha', { digit })}
onChange={(e) => { onChange={(e) => {
inputChange('captcha', e.target.value); inputChange('captcha', e.target.value);
}} }}