feat: 密码登录方式调整至系统配置管理下
This commit is contained in:
parent
5fb1988b0d
commit
5b702a0d7d
|
|
@ -536,23 +536,9 @@ export async function loginByMobile(params, context) {
|
|||
}
|
||||
export async function verifyPassword(params, context) {
|
||||
const { password } = params;
|
||||
const systemId = context.getSystemId();
|
||||
const [pwdPassport] = await context.select('passport', {
|
||||
data: {
|
||||
id: 1,
|
||||
systemId: 1,
|
||||
config: 1,
|
||||
type: 1,
|
||||
enabled: 1,
|
||||
},
|
||||
filter: {
|
||||
systemId,
|
||||
enabled: true,
|
||||
type: 'password',
|
||||
}
|
||||
}, { forUpdate: true });
|
||||
// assert(pwdPassport);
|
||||
const pwdMode = pwdPassport?.config?.mode ?? 'all';
|
||||
const { system } = context.getApplication();
|
||||
const pwdConfig = system?.config.Password;
|
||||
const pwdMode = pwdConfig?.mode ?? 'all';
|
||||
let pwdFilter = {};
|
||||
if (pwdMode === 'all') {
|
||||
pwdFilter = {
|
||||
|
|
@ -664,13 +650,15 @@ export async function loginByAccount(params, context) {
|
|||
id: 1,
|
||||
type: 1,
|
||||
systemId: 1,
|
||||
}
|
||||
},
|
||||
allowPwd: 1,
|
||||
},
|
||||
filter: {
|
||||
passport: {
|
||||
systemId,
|
||||
},
|
||||
applicationId,
|
||||
allowPwd: true,
|
||||
}
|
||||
}, {
|
||||
dontCollect: true,
|
||||
|
|
@ -761,13 +749,15 @@ export async function loginByAccount(params, context) {
|
|||
id: 1,
|
||||
type: 1,
|
||||
systemId: 1,
|
||||
}
|
||||
},
|
||||
allowPwd: 1,
|
||||
},
|
||||
filter: {
|
||||
passport: {
|
||||
systemId,
|
||||
},
|
||||
applicationId,
|
||||
allowPwd: true,
|
||||
}
|
||||
}, {
|
||||
dontCollect: true,
|
||||
|
|
@ -875,29 +865,9 @@ export async function loginByAccount(params, context) {
|
|||
}
|
||||
};
|
||||
const closeRootMode = context.openRootMode();
|
||||
const application = context.getApplication();
|
||||
const [applicationPassport] = await context.select('applicationPassport', {
|
||||
data: {
|
||||
id: 1,
|
||||
passportId: 1,
|
||||
passport: {
|
||||
id: 1,
|
||||
config: 1,
|
||||
type: 1,
|
||||
},
|
||||
applicationId: 1,
|
||||
},
|
||||
filter: {
|
||||
applicationId: application?.id,
|
||||
passport: {
|
||||
type: 'password',
|
||||
},
|
||||
}
|
||||
}, {
|
||||
dontCollect: true,
|
||||
});
|
||||
// assert(applicationPassport?.passport);
|
||||
const pwdMode = applicationPassport?.passport?.config?.mode ?? 'all';
|
||||
const { system } = context.getApplication();
|
||||
const pwdConfig = system?.config.Password;
|
||||
const pwdMode = pwdConfig?.mode ?? 'all';
|
||||
let pwdFilter = {}, updateData = {};
|
||||
if (pwdMode === 'all') {
|
||||
pwdFilter = {
|
||||
|
|
@ -2546,8 +2516,8 @@ export async function refreshToken(params, context) {
|
|||
// 只有server模式去刷新token
|
||||
// 'development' | 'production' | 'staging'
|
||||
const intervals = {
|
||||
development: 7200 * 1000,
|
||||
staging: 600 * 1000,
|
||||
development: 7200 * 1000, // 2小时
|
||||
staging: 600 * 1000, // 十分钟
|
||||
production: 600 * 1000, // 十分钟
|
||||
};
|
||||
let applicationId = token.applicationId;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
/// <reference types="wechat-miniprogram" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "user", false, WechatMiniprogram.Component.DataOption>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -54,9 +54,8 @@ export default OakComponent({
|
|||
lifetimes: {
|
||||
async ready() {
|
||||
const lastSendAt = await this.load(SEND_KEY);
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig = applicationPassports.find((ele) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
/// <reference types="wechat-miniprogram" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "user", false, WechatMiniprogram.Component.DataOption>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -23,9 +23,8 @@ export default OakComponent({
|
|||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig = applicationPassports.find((ele) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Style } from '../../../../types/Style';
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../../oak-app-domain").EntityDict, keyof import("../../../../oak-app-domain").EntityDict, false, {
|
||||
style: Style;
|
||||
entity: "platform" | "system" | "application";
|
||||
entity: "system" | "platform" | "application";
|
||||
entityId: string;
|
||||
name: string;
|
||||
}>) => React.ReactElement;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Config } from '../../../types/Config';
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
|
||||
config: Config;
|
||||
entity: "platform" | "system";
|
||||
entity: "system" | "platform";
|
||||
name: string;
|
||||
entityId: string;
|
||||
}>) => React.ReactElement;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
import React from 'react';
|
||||
import { Config } from '../../../../types/Config';
|
||||
export default function Security(props: {
|
||||
password: Required<Config>['Password'];
|
||||
setValue: (path: string, value: any) => void;
|
||||
setValues: (value: Record<string, any>) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Col, Divider, Input, Form, Space, Radio, InputNumber, Switch, } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
import EditorRegexs from '../../../passport/password/editorRegexs';
|
||||
export default function Security(props) {
|
||||
const { password, setValue, setValues } = props;
|
||||
const { mode, min, max, verify, regexs, tip } = password || {};
|
||||
const [newTip, setNewTip] = useState('');
|
||||
useEffect(() => {
|
||||
const { password } = props;
|
||||
if (!password.mode) {
|
||||
setValues({
|
||||
mode: 'all',
|
||||
min: 8,
|
||||
max: 24,
|
||||
});
|
||||
}
|
||||
}, [password]);
|
||||
useEffect(() => {
|
||||
if (tip && !newTip) {
|
||||
setNewTip(tip);
|
||||
}
|
||||
}, [tip]);
|
||||
return (<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||
<Col flex="auto">
|
||||
<Divider orientation="left" className={Styles.title}>
|
||||
密码设置
|
||||
</Divider>
|
||||
<Form labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} style={{ maxWidth: 600 }}>
|
||||
<Form.Item label="密码存储模式" tooltip="密码存储模式">
|
||||
<Radio.Group onChange={({ target }) => {
|
||||
const { value } = target;
|
||||
setValue('mode', value);
|
||||
}} value={mode}>
|
||||
<Radio value="all">明文与SHA1加密</Radio>
|
||||
<Radio value="plain">仅明文</Radio>
|
||||
<Radio value="sha1">仅SHA1加密</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="密码位数范围" tooltip="密码位数范围">
|
||||
<Space>
|
||||
<InputNumber min={1} max={max} value={min} onChange={(value) => {
|
||||
setValue('min', value);
|
||||
}}/>
|
||||
<div>~</div>
|
||||
<InputNumber min={min} value={max} onChange={(value) => {
|
||||
setValue('max', value);
|
||||
}}/>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="开启正则校验" tooltip="开启后将使用下方设置的正则表达式对密码进行校验">
|
||||
<Switch checkedChildren="开启" unCheckedChildren="关闭" checked={!!verify} onChange={(checked) => {
|
||||
setValue('verigy', checked);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="正则" tooltip="可同时设置多组正则,系统将按照【与】逻辑进行校验,每个正则请以^开头以$结尾">
|
||||
<>
|
||||
{!!verify ? (<>
|
||||
<EditorRegexs regexs={regexs || []} updateRegexs={(regexs) => {
|
||||
setValue('regexs', regexs);
|
||||
}}/>
|
||||
</>) : (<div>暂未启用正则校验,无需设置</div>)}
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item label="密码提示语" tooltip="此提示语将显示在用户设置密码的输入框附近,用于清晰告知用户密码的格式要求">
|
||||
<Input placeholder="请输入密码提示语" type="text" value={tip} onChange={(e) => {
|
||||
setNewTip(e.target.value);
|
||||
}} onBlur={() => {
|
||||
if (newTip && newTip !== tip) {
|
||||
setValue('tip', newTip);
|
||||
}
|
||||
}}/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Col>
|
||||
</Space>);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
.label {
|
||||
color: var(--oak-text-color-primary);
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: var(--oak-text-color-placeholder);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 0px;
|
||||
margin-top:36px;
|
||||
}
|
||||
|
|
@ -9,10 +9,11 @@ import Sms from './sms/index';
|
|||
import Email from './email/index';
|
||||
import Basic from './basic/index';
|
||||
import Security from './security/index';
|
||||
import Password from './password/index';
|
||||
export default function Render(props) {
|
||||
const { entity, name, currentConfig, dirty } = props.data;
|
||||
const { resetConfig, updateConfig, setValue, setValues, removeItem, cleanKey, t } = props.methods;
|
||||
const { Account: account, Cos: cos, Map: map, Live: live, Sms: sms, App: app, Emails: emails, Security: security, } = currentConfig || {};
|
||||
const { Account: account, Cos: cos, Map: map, Live: live, Sms: sms, App: app, Emails: emails, Security: security, Password: password, } = currentConfig || {};
|
||||
return (<>
|
||||
<Affix offsetTop={64}>
|
||||
<Alert message={<div>
|
||||
|
|
@ -84,6 +85,15 @@ export default function Render(props) {
|
|||
});
|
||||
}}/>),
|
||||
},
|
||||
{
|
||||
key: '密码设置',
|
||||
label: '密码设置',
|
||||
children: (<Password password={password || {}} setValue={(path, value) => setValue(`Password.${path}`, value)} setValues={(value) => {
|
||||
setValues({
|
||||
Password: value
|
||||
});
|
||||
}}/>),
|
||||
},
|
||||
]}></Tabs>
|
||||
</div>
|
||||
</>);
|
||||
|
|
|
|||
|
|
@ -34,9 +34,8 @@ export default OakComponent({
|
|||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig = applicationPassports.find((ele) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../../oak-app-domain").EntityDict, keyof import("../../../../oak-app-domain").EntityDict, boolean, {
|
||||
onVerified: (() => void) | undefined;
|
||||
onVerified: undefined | (() => void);
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@ export default OakComponent({
|
|||
lifetimes: {
|
||||
async ready() {
|
||||
this.features.token.getToken();
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig = applicationPassports.find((ele) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
this.setState({
|
||||
mode,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/// <reference types="react" />
|
||||
import { WebComponentProps } from "oak-frontend-base";
|
||||
import { EntityDict } from "../../../../oak-app-domain";
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'user', false, {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/// <reference types="react" />
|
||||
import { WebComponentProps } from "oak-frontend-base";
|
||||
import { EntityDict } from "../../../../oak-app-domain";
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'user', false, {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
|||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
||||
entity: keyof ED2;
|
||||
entityId: string;
|
||||
relations: EntityDict['relation']['OpSchema'][];
|
||||
passwordRequired?: boolean | undefined;
|
||||
allowUpdateName?: boolean | undefined;
|
||||
allowUpdateNickname?: boolean | undefined;
|
||||
relations: EntityDict["relation"]["OpSchema"][];
|
||||
passwordRequired?: boolean;
|
||||
allowUpdateName?: boolean;
|
||||
allowUpdateNickname?: boolean;
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
|||
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
|
||||
entity: keyof ED2;
|
||||
entityId: string;
|
||||
allowUpdateName?: boolean | undefined;
|
||||
allowUpdateNickname?: boolean | undefined;
|
||||
allowUpdateName?: boolean;
|
||||
allowUpdateNickname?: boolean;
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
|
|||
entityId: string;
|
||||
redirectToAfterConfirm: ED2["userEntityGrant"]["Schema"]["redirectTo"];
|
||||
qrCodeType: QrCodeType;
|
||||
type: EntityDict['userEntityGrant']['Schema']['type'];
|
||||
relations: EntityDict['relation']['OpSchema'][];
|
||||
type: EntityDict["userEntityGrant"]["Schema"]["type"];
|
||||
relations: EntityDict["relation"]["OpSchema"][];
|
||||
claimUrl: string;
|
||||
multiple: boolean;
|
||||
rule: EntityDict['userEntityGrant']['Schema']['rule'];
|
||||
ruleOnRow: EntityDict['userEntityGrant']['OpSchema']['ruleOnRow'];
|
||||
onUserEntityGrantCreated?: ((id: string) => void) | undefined;
|
||||
rule: EntityDict["userEntityGrant"]["Schema"]["rule"];
|
||||
ruleOnRow: EntityDict["userEntityGrant"]["OpSchema"]["ruleOnRow"];
|
||||
onUserEntityGrantCreated?: (id: string) => void;
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
|
|||
redirectToAfterConfirm: ED2["userEntityGrant"]["Schema"]["redirectTo"];
|
||||
claimUrl: string;
|
||||
qrCodeType: string;
|
||||
passwordRequired?: boolean | undefined;
|
||||
disabledMethods: Array<'email' | 'mobile' | 'userEntityGrant'>;
|
||||
mode: 'byMobile' | 'byUserEntityGrant' | 'byEmail';
|
||||
passwordRequired?: boolean;
|
||||
disabledMethods: Array<"email" | "mobile" | "userEntityGrant">;
|
||||
mode: "byMobile" | "byUserEntityGrant" | "byEmail";
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { EntityDict } from '../../../../oak-app-domain';
|
|||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "user", false, {
|
||||
entity: keyof EntityDict;
|
||||
entityId: string;
|
||||
relations: import("../../../../oak-app-domain/Relation/_baseSchema").OpSchema[];
|
||||
relations: EntityDict["relation"]["OpSchema"][];
|
||||
mobile: string;
|
||||
setPasswordConfirm: (value: boolean) => void;
|
||||
passwordRequired: boolean;
|
||||
|
|
|
|||
|
|
@ -84,9 +84,8 @@ export default OakComponent({
|
|||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig = applicationPassports.find((ele) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ import { EntityDict } from '../../../../../oak-app-domain';
|
|||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "userRelation", true, {
|
||||
entity: keyof EntityDict;
|
||||
entityId: string;
|
||||
relations: import("../../../../../oak-app-domain/Relation/_baseSchema").OpSchema[];
|
||||
relations: EntityDict["relation"]["OpSchema"][];
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -151,6 +151,14 @@ export type EmailConfig = {
|
|||
name?: string;
|
||||
secure?: boolean;
|
||||
};
|
||||
export type PasswordConfig = {
|
||||
mode?: 'all' | 'plain' | 'sha1';
|
||||
min?: number;
|
||||
max?: number;
|
||||
verify?: boolean;
|
||||
regexs?: string[];
|
||||
tip?: string;
|
||||
};
|
||||
export type QrCodeType = 'wechatMpDomainUrl' | 'wechatMpWxaCode' | 'wechatPublic' | 'wechatPublicForMp' | 'webForWechatPublic';
|
||||
export type Config = {
|
||||
Account?: {
|
||||
|
|
@ -202,6 +210,7 @@ export type Config = {
|
|||
level?: 'weak' | 'medium' | 'strong';
|
||||
passwordVerifyGap?: number;
|
||||
};
|
||||
Password?: PasswordConfig;
|
||||
};
|
||||
export type AccountOrigin = 'ali' | 'tencent' | 'qiniu' | 'amap' | 'ctyun' | 'local' | 's3';
|
||||
export type CosOrigin = 'qiniu' | 'wechat' | 'ctyun' | 'aliyun' | 'tencent' | 'local' | 'unknown' | 's3';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,28 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.loginWebByMpToken = exports.refreshToken = exports.wakeupParasite = exports.logout = exports.getWechatMpUserPhoneNumber = exports.switchTo = exports.sendCaptchaByEmail = exports.sendCaptchaByMobile = exports.syncUserInfoWechatMp = exports.loginWechatMp = exports.loginWechat = exports.loginWechatNative = exports.loginByWechat = exports.refreshWechatPublicUserInfo = exports.setUserAvatarFromWechat = exports.bindByEmail = exports.bindByMobile = exports.loginByEmail = exports.loginByAccount = exports.verifyPassword = exports.loginByMobile = exports.loadTokenInfo = exports.setUpTokenAndUser = void 0;
|
||||
exports.setUpTokenAndUser = setUpTokenAndUser;
|
||||
exports.loadTokenInfo = loadTokenInfo;
|
||||
exports.loginByMobile = loginByMobile;
|
||||
exports.verifyPassword = verifyPassword;
|
||||
exports.loginByAccount = loginByAccount;
|
||||
exports.loginByEmail = loginByEmail;
|
||||
exports.bindByMobile = bindByMobile;
|
||||
exports.bindByEmail = bindByEmail;
|
||||
exports.setUserAvatarFromWechat = setUserAvatarFromWechat;
|
||||
exports.refreshWechatPublicUserInfo = refreshWechatPublicUserInfo;
|
||||
exports.loginByWechat = loginByWechat;
|
||||
exports.loginWechatNative = loginWechatNative;
|
||||
exports.loginWechat = loginWechat;
|
||||
exports.loginWechatMp = loginWechatMp;
|
||||
exports.syncUserInfoWechatMp = syncUserInfoWechatMp;
|
||||
exports.sendCaptchaByMobile = sendCaptchaByMobile;
|
||||
exports.sendCaptchaByEmail = sendCaptchaByEmail;
|
||||
exports.switchTo = switchTo;
|
||||
exports.getWechatMpUserPhoneNumber = getWechatMpUserPhoneNumber;
|
||||
exports.logout = logout;
|
||||
exports.wakeupParasite = wakeupParasite;
|
||||
exports.refreshToken = refreshToken;
|
||||
exports.loginWebByMpToken = loginWebByMpToken;
|
||||
const tslib_1 = require("tslib");
|
||||
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
||||
const WechatSDK_1 = tslib_1.__importDefault(require("oak-external-sdk/lib/WechatSDK"));
|
||||
|
|
@ -380,7 +402,6 @@ createData, user) {
|
|||
}
|
||||
}
|
||||
}
|
||||
exports.setUpTokenAndUser = setUpTokenAndUser;
|
||||
async function setupMobile(mobile, env, context) {
|
||||
const result2 = await context.select('mobile', {
|
||||
data: {
|
||||
|
|
@ -444,7 +465,6 @@ async function loadTokenInfo(tokenValue, context) {
|
|||
},
|
||||
}, {});
|
||||
}
|
||||
exports.loadTokenInfo = loadTokenInfo;
|
||||
async function loginByMobile(params, context) {
|
||||
const { mobile, captcha, env, disableRegister } = params;
|
||||
const loginLogic = async (isRoot) => {
|
||||
|
|
@ -540,26 +560,11 @@ async function loginByMobile(params, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginByMobile = loginByMobile;
|
||||
async function verifyPassword(params, context) {
|
||||
const { password } = params;
|
||||
const systemId = context.getSystemId();
|
||||
const [pwdPassport] = await context.select('passport', {
|
||||
data: {
|
||||
id: 1,
|
||||
systemId: 1,
|
||||
config: 1,
|
||||
type: 1,
|
||||
enabled: 1,
|
||||
},
|
||||
filter: {
|
||||
systemId,
|
||||
enabled: true,
|
||||
type: 'password',
|
||||
}
|
||||
}, { forUpdate: true });
|
||||
// assert(pwdPassport);
|
||||
const pwdMode = pwdPassport?.config?.mode ?? 'all';
|
||||
const { system } = context.getApplication();
|
||||
const pwdConfig = system?.config.Password;
|
||||
const pwdMode = pwdConfig?.mode ?? 'all';
|
||||
let pwdFilter = {};
|
||||
if (pwdMode === 'all') {
|
||||
pwdFilter = {
|
||||
|
|
@ -605,7 +610,6 @@ async function verifyPassword(params, context) {
|
|||
}
|
||||
}, {});
|
||||
}
|
||||
exports.verifyPassword = verifyPassword;
|
||||
async function loginByAccount(params, context) {
|
||||
const { account, password, env } = params;
|
||||
let needUpdatePassword = false;
|
||||
|
|
@ -672,13 +676,15 @@ async function loginByAccount(params, context) {
|
|||
id: 1,
|
||||
type: 1,
|
||||
systemId: 1,
|
||||
}
|
||||
},
|
||||
allowPwd: 1,
|
||||
},
|
||||
filter: {
|
||||
passport: {
|
||||
systemId,
|
||||
},
|
||||
applicationId,
|
||||
allowPwd: true,
|
||||
}
|
||||
}, {
|
||||
dontCollect: true,
|
||||
|
|
@ -769,13 +775,15 @@ async function loginByAccount(params, context) {
|
|||
id: 1,
|
||||
type: 1,
|
||||
systemId: 1,
|
||||
}
|
||||
},
|
||||
allowPwd: 1,
|
||||
},
|
||||
filter: {
|
||||
passport: {
|
||||
systemId,
|
||||
},
|
||||
applicationId,
|
||||
allowPwd: true,
|
||||
}
|
||||
}, {
|
||||
dontCollect: true,
|
||||
|
|
@ -883,29 +891,9 @@ async function loginByAccount(params, context) {
|
|||
}
|
||||
};
|
||||
const closeRootMode = context.openRootMode();
|
||||
const application = context.getApplication();
|
||||
const [applicationPassport] = await context.select('applicationPassport', {
|
||||
data: {
|
||||
id: 1,
|
||||
passportId: 1,
|
||||
passport: {
|
||||
id: 1,
|
||||
config: 1,
|
||||
type: 1,
|
||||
},
|
||||
applicationId: 1,
|
||||
},
|
||||
filter: {
|
||||
applicationId: application?.id,
|
||||
passport: {
|
||||
type: 'password',
|
||||
},
|
||||
}
|
||||
}, {
|
||||
dontCollect: true,
|
||||
});
|
||||
// assert(applicationPassport?.passport);
|
||||
const pwdMode = applicationPassport?.passport?.config?.mode ?? 'all';
|
||||
const { system } = context.getApplication();
|
||||
const pwdConfig = system?.config.Password;
|
||||
const pwdMode = pwdConfig?.mode ?? 'all';
|
||||
let pwdFilter = {}, updateData = {};
|
||||
if (pwdMode === 'all') {
|
||||
pwdFilter = {
|
||||
|
|
@ -958,7 +946,6 @@ async function loginByAccount(params, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginByAccount = loginByAccount;
|
||||
async function loginByEmail(params, context) {
|
||||
const { email, captcha, env, disableRegister } = params;
|
||||
const loginLogic = async () => {
|
||||
|
|
@ -1029,7 +1016,6 @@ async function loginByEmail(params, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginByEmail = loginByEmail;
|
||||
async function bindByMobile(params, context) {
|
||||
const { mobile, captcha, env, } = params;
|
||||
const userId = context.getCurrentUserId();
|
||||
|
|
@ -1141,7 +1127,6 @@ async function bindByMobile(params, context) {
|
|||
await bindLogic();
|
||||
closeRootMode();
|
||||
}
|
||||
exports.bindByMobile = bindByMobile;
|
||||
async function bindByEmail(params, context) {
|
||||
const { email, captcha, env, } = params;
|
||||
const userId = context.getCurrentUserId();
|
||||
|
|
@ -1254,7 +1239,6 @@ async function bindByEmail(params, context) {
|
|||
await bindLogic();
|
||||
closeRootMode();
|
||||
}
|
||||
exports.bindByEmail = bindByEmail;
|
||||
async function setupLoginName(name, env, context) {
|
||||
const result2 = await context.select('loginName', {
|
||||
data: {
|
||||
|
|
@ -1495,7 +1479,6 @@ async function setUserAvatarFromWechat(params, context) {
|
|||
}, {});
|
||||
}
|
||||
}
|
||||
exports.setUserAvatarFromWechat = setUserAvatarFromWechat;
|
||||
async function tryRefreshWechatPublicUserInfo(wechatUserId, context) {
|
||||
const [wechatUser] = await context.select('wechatUser', {
|
||||
data: {
|
||||
|
|
@ -1584,7 +1567,6 @@ async function refreshWechatPublicUserInfo({}, context) {
|
|||
(0, assert_1.assert)(token.entityId);
|
||||
return await tryRefreshWechatPublicUserInfo(token.entityId, context);
|
||||
}
|
||||
exports.refreshWechatPublicUserInfo = refreshWechatPublicUserInfo;
|
||||
// 用户在微信端授权登录后,在web端触发该方法
|
||||
async function loginByWechat(params, context) {
|
||||
const { wechatLoginId, env } = params;
|
||||
|
|
@ -1614,7 +1596,6 @@ async function loginByWechat(params, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginByWechat = loginByWechat;
|
||||
async function loginFromWechatEnv(code, env, context, wechatLoginId) {
|
||||
const application = context.getApplication();
|
||||
const { type, config, systemId } = application;
|
||||
|
|
@ -1958,7 +1939,6 @@ async function loginWechatNative({ code, env, }, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginWechatNative = loginWechatNative;
|
||||
/**
|
||||
* 公众号授权登录
|
||||
* @param param0
|
||||
|
|
@ -1989,7 +1969,6 @@ async function loginWechat({ code, env, wechatLoginId, }, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginWechat = loginWechat;
|
||||
/**
|
||||
* 小程序授权登录
|
||||
* @param param0
|
||||
|
|
@ -2003,7 +1982,6 @@ async function loginWechatMp({ code, env, }, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginWechatMp = loginWechatMp;
|
||||
/**
|
||||
* 同步从wx.getUserProfile拿到的用户信息
|
||||
* @param param0
|
||||
|
|
@ -2057,7 +2035,6 @@ async function syncUserInfoWechatMp({ nickname, avatarUrl, encryptedData, iv, si
|
|||
// 实测发现解密出来的和userInfo完全一致……
|
||||
await setUserInfoFromWechat(user, { nickname, avatar: avatarUrl }, context);
|
||||
}
|
||||
exports.syncUserInfoWechatMp = syncUserInfoWechatMp;
|
||||
async function sendCaptchaByMobile({ mobile, env, type: captchaType, }, context) {
|
||||
const { type } = env;
|
||||
let visitorId = mobile;
|
||||
|
|
@ -2222,7 +2199,6 @@ async function sendCaptchaByMobile({ mobile, env, type: captchaType, }, context)
|
|||
return '验证码发送失败';
|
||||
}
|
||||
}
|
||||
exports.sendCaptchaByMobile = sendCaptchaByMobile;
|
||||
async function sendCaptchaByEmail({ email, env, type: captchaType, }, context) {
|
||||
const { type } = env;
|
||||
let visitorId = email;
|
||||
|
|
@ -2370,7 +2346,6 @@ async function sendCaptchaByEmail({ email, env, type: captchaType, }, context) {
|
|||
return '验证码发送失败';
|
||||
}
|
||||
}
|
||||
exports.sendCaptchaByEmail = sendCaptchaByEmail;
|
||||
async function switchTo({ userId }, context) {
|
||||
const reallyRoot = context.isReallyRoot();
|
||||
if (!reallyRoot) {
|
||||
|
|
@ -2392,7 +2367,6 @@ async function switchTo({ userId }, context) {
|
|||
},
|
||||
}, {});
|
||||
}
|
||||
exports.switchTo = switchTo;
|
||||
async function getWechatMpUserPhoneNumber({ code, env }, context) {
|
||||
const application = context.getApplication();
|
||||
const { type, config, systemId } = application;
|
||||
|
|
@ -2408,7 +2382,6 @@ async function getWechatMpUserPhoneNumber({ code, env }, context) {
|
|||
closeRootMode();
|
||||
return reuslt;
|
||||
}
|
||||
exports.getWechatMpUserPhoneNumber = getWechatMpUserPhoneNumber;
|
||||
async function logout(params, context) {
|
||||
const { tokenValue } = params;
|
||||
if (tokenValue) {
|
||||
|
|
@ -2431,7 +2404,6 @@ async function logout(params, context) {
|
|||
closeRootMode();
|
||||
}
|
||||
}
|
||||
exports.logout = logout;
|
||||
/**
|
||||
* 创建一个当前parasite上的token
|
||||
* @param params
|
||||
|
|
@ -2498,7 +2470,6 @@ async function wakeupParasite(params, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.wakeupParasite = wakeupParasite;
|
||||
/**
|
||||
* todo 检查登录环境一致性,同一个token不能跨越不同设备
|
||||
* @param env1
|
||||
|
|
@ -2571,8 +2542,8 @@ async function refreshToken(params, context) {
|
|||
// 只有server模式去刷新token
|
||||
// 'development' | 'production' | 'staging'
|
||||
const intervals = {
|
||||
development: 7200 * 1000,
|
||||
staging: 600 * 1000,
|
||||
development: 7200 * 1000, // 2小时
|
||||
staging: 600 * 1000, // 十分钟
|
||||
production: 600 * 1000, // 十分钟
|
||||
};
|
||||
let applicationId = token.applicationId;
|
||||
|
|
@ -2645,7 +2616,6 @@ async function refreshToken(params, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.refreshToken = refreshToken;
|
||||
/**
|
||||
* 使用微信小程序中的token登录web
|
||||
* @param tokenValue
|
||||
|
|
@ -2713,4 +2683,3 @@ async function loginWebByMpToken(params, context) {
|
|||
closeRootMode();
|
||||
return tokenValue;
|
||||
}
|
||||
exports.loginWebByMpToken = loginWebByMpToken;
|
||||
|
|
|
|||
|
|
@ -151,6 +151,14 @@ export type EmailConfig = {
|
|||
name?: string;
|
||||
secure?: boolean;
|
||||
};
|
||||
export type PasswordConfig = {
|
||||
mode?: 'all' | 'plain' | 'sha1';
|
||||
min?: number;
|
||||
max?: number;
|
||||
verify?: boolean;
|
||||
regexs?: string[];
|
||||
tip?: string;
|
||||
};
|
||||
export type QrCodeType = 'wechatMpDomainUrl' | 'wechatMpWxaCode' | 'wechatPublic' | 'wechatPublicForMp' | 'webForWechatPublic';
|
||||
export type Config = {
|
||||
Account?: {
|
||||
|
|
@ -202,6 +210,7 @@ export type Config = {
|
|||
level?: 'weak' | 'medium' | 'strong';
|
||||
passwordVerifyGap?: number;
|
||||
};
|
||||
Password?: PasswordConfig;
|
||||
};
|
||||
export type AccountOrigin = 'ali' | 'tencent' | 'qiniu' | 'amap' | 'ctyun' | 'local' | 's3';
|
||||
export type CosOrigin = 'qiniu' | 'wechat' | 'ctyun' | 'aliyun' | 'tencent' | 'local' | 'unknown' | 's3';
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import { sendSms } from '../utils/sms';
|
|||
import { mergeUser } from './user';
|
||||
import { cloneDeep, pick } from 'oak-domain/lib/utils/lodash';
|
||||
import { BRC } from '../types/RuntimeCxt';
|
||||
import { PwdConfig, SmsConfig } from '../entities/Passport';
|
||||
import { SmsConfig } from '../entities/Passport';
|
||||
import { sendEmail } from '../utils/email';
|
||||
import { EmailConfig } from '../oak-app-domain/Passport/Schema';
|
||||
import { isEmail, isMobile } from 'oak-domain/lib/utils/validator';
|
||||
|
|
@ -730,23 +730,9 @@ export async function verifyPassword<ED extends EntityDict>(
|
|||
context: BRC<ED>
|
||||
) {
|
||||
const { password } = params;
|
||||
const systemId = context.getSystemId();
|
||||
const [pwdPassport] = await context.select('passport', {
|
||||
data: {
|
||||
id: 1,
|
||||
systemId: 1,
|
||||
config: 1,
|
||||
type: 1,
|
||||
enabled: 1,
|
||||
},
|
||||
filter: {
|
||||
systemId,
|
||||
enabled: true,
|
||||
type: 'password',
|
||||
}
|
||||
}, { forUpdate: true });
|
||||
// assert(pwdPassport);
|
||||
const pwdMode = (pwdPassport?.config as PwdConfig)?.mode ?? 'all';
|
||||
const { system } = context.getApplication()!;
|
||||
const pwdConfig = system?.config.Password;
|
||||
const pwdMode = pwdConfig?.mode ?? 'all';
|
||||
let pwdFilter = {};
|
||||
if (pwdMode === 'all') {
|
||||
pwdFilter = {
|
||||
|
|
@ -881,13 +867,15 @@ export async function loginByAccount<ED extends EntityDict>(
|
|||
id: 1,
|
||||
type: 1,
|
||||
systemId: 1,
|
||||
}
|
||||
},
|
||||
allowPwd: 1,
|
||||
},
|
||||
filter: {
|
||||
passport: {
|
||||
systemId,
|
||||
},
|
||||
applicationId,
|
||||
allowPwd: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -991,13 +979,15 @@ export async function loginByAccount<ED extends EntityDict>(
|
|||
id: 1,
|
||||
type: 1,
|
||||
systemId: 1,
|
||||
}
|
||||
},
|
||||
allowPwd: 1,
|
||||
},
|
||||
filter: {
|
||||
passport: {
|
||||
systemId,
|
||||
},
|
||||
applicationId,
|
||||
allowPwd: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1119,32 +1109,9 @@ export async function loginByAccount<ED extends EntityDict>(
|
|||
}
|
||||
};
|
||||
const closeRootMode = context.openRootMode();
|
||||
const application = context.getApplication();
|
||||
const [applicationPassport] = await context.select('applicationPassport',
|
||||
{
|
||||
data: {
|
||||
id: 1,
|
||||
passportId: 1,
|
||||
passport: {
|
||||
id: 1,
|
||||
config: 1,
|
||||
type: 1,
|
||||
},
|
||||
applicationId: 1,
|
||||
},
|
||||
filter: {
|
||||
applicationId: application?.id!,
|
||||
passport: {
|
||||
type: 'password',
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
dontCollect: true,
|
||||
}
|
||||
);
|
||||
// assert(applicationPassport?.passport);
|
||||
const pwdMode = (applicationPassport?.passport?.config as PwdConfig)?.mode ?? 'all';
|
||||
const { system } = context.getApplication()!;
|
||||
const pwdConfig = system?.config.Password;
|
||||
const pwdMode = pwdConfig?.mode ?? 'all';
|
||||
let pwdFilter = {}, updateData = {};
|
||||
if (pwdMode === 'all') {
|
||||
pwdFilter = {
|
||||
|
|
@ -3324,7 +3291,7 @@ export async function refreshToken<ED extends EntityDict>(
|
|||
if (!token) {
|
||||
throw new OakUnloggedInException("Token令牌已失效,请重新登录");
|
||||
}
|
||||
|
||||
|
||||
const now = Date.now();
|
||||
if (!checkTokenEnvConsistency(env, token.env as WebEnv)) {
|
||||
console.log('####### refreshToken 环境改变 start #######\n');
|
||||
|
|
|
|||
|
|
@ -63,9 +63,8 @@ export default OakComponent({
|
|||
lifetimes: {
|
||||
async ready() {
|
||||
const lastSendAt = await this.load(SEND_KEY);
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig: PwdConfig = applicationPassports.find((ele: EntityDict['applicationPassport']['Schema']) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -26,9 +26,8 @@ export default OakComponent({
|
|||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig: PwdConfig = applicationPassports.find((ele: EntityDict['applicationPassport']['Schema']) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Tabs,
|
||||
Row,
|
||||
Col,
|
||||
Card,
|
||||
Divider,
|
||||
Input,
|
||||
Form,
|
||||
Space,
|
||||
Select,
|
||||
Radio,
|
||||
InputNumber,
|
||||
Switch,
|
||||
} from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
import { Config } from '../../../../types/Config';
|
||||
import EditorRegexs from '../../../passport/password/editorRegexs';
|
||||
|
||||
export default function Security(props: {
|
||||
password: Required<Config>['Password'];
|
||||
setValue: (path: string, value: any) => void;
|
||||
setValues: (value: Record<string, any>) => void;
|
||||
}) {
|
||||
const { password, setValue, setValues } = props;
|
||||
const { mode, min, max, verify, regexs, tip } = password || {};
|
||||
const [newTip, setNewTip] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const { password } = props;
|
||||
if (!password.mode) {
|
||||
setValues({
|
||||
mode: 'all',
|
||||
min: 8,
|
||||
max: 24,
|
||||
});
|
||||
}
|
||||
}, [password]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tip && !newTip) {
|
||||
setNewTip(tip)
|
||||
}
|
||||
}, [tip]);
|
||||
|
||||
return (
|
||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||
<Col flex="auto">
|
||||
<Divider orientation="left" className={Styles.title}>
|
||||
密码设置
|
||||
</Divider>
|
||||
<Form
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
style={{ maxWidth: 600 }}
|
||||
>
|
||||
<Form.Item
|
||||
label="密码存储模式"
|
||||
tooltip="密码存储模式"
|
||||
>
|
||||
<Radio.Group
|
||||
onChange={({ target }) => {
|
||||
const { value } = target;
|
||||
setValue('mode', value);
|
||||
}}
|
||||
value={mode}
|
||||
>
|
||||
<Radio value="all">明文与SHA1加密</Radio>
|
||||
<Radio value="plain">仅明文</Radio>
|
||||
<Radio value="sha1">仅SHA1加密</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="密码位数范围"
|
||||
tooltip="密码位数范围"
|
||||
>
|
||||
<Space>
|
||||
<InputNumber min={1} max={max} value={min} onChange={(value) => {
|
||||
setValue('min', value);
|
||||
}} />
|
||||
<div>~</div>
|
||||
<InputNumber min={min} value={max} onChange={(value) => {
|
||||
setValue('max', value);
|
||||
}} />
|
||||
</Space>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="开启正则校验"
|
||||
tooltip="开启后将使用下方设置的正则表达式对密码进行校验"
|
||||
>
|
||||
<Switch
|
||||
checkedChildren="开启"
|
||||
unCheckedChildren="关闭"
|
||||
checked={!!verify}
|
||||
onChange={(checked) => {
|
||||
setValue('verigy', checked)
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="正则"
|
||||
tooltip="可同时设置多组正则,系统将按照【与】逻辑进行校验,每个正则请以^开头以$结尾"
|
||||
>
|
||||
<>
|
||||
{!!verify ? (
|
||||
<>
|
||||
<EditorRegexs regexs={regexs || []} updateRegexs={(regexs) => {
|
||||
setValue('regexs', regexs);
|
||||
}} />
|
||||
</>
|
||||
) : (
|
||||
<div>暂未启用正则校验,无需设置</div>
|
||||
)}
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item label="密码提示语" tooltip="此提示语将显示在用户设置密码的输入框附近,用于清晰告知用户密码的格式要求">
|
||||
<Input
|
||||
placeholder="请输入密码提示语"
|
||||
type="text"
|
||||
value={tip}
|
||||
onChange={(e) => {
|
||||
setNewTip(e.target.value);
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (newTip && newTip !== tip) {
|
||||
setValue('tip', newTip);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Col>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
.label {
|
||||
color: var(--oak-text-color-primary);
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: var(--oak-text-color-placeholder);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 0px;
|
||||
margin-top:36px;
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import Sms from './sms/index';
|
|||
import Email from './email/index';
|
||||
import Basic from './basic/index';
|
||||
import Security from './security/index';
|
||||
import Password from './password/index';
|
||||
import { Config } from '../../../types/Config';
|
||||
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
|
|
@ -47,6 +48,7 @@ export default function Render(
|
|||
App: app,
|
||||
Emails: emails,
|
||||
Security: security,
|
||||
Password: password,
|
||||
} = currentConfig || {};
|
||||
return (
|
||||
<>
|
||||
|
|
@ -228,6 +230,23 @@ export default function Render(
|
|||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: '密码设置',
|
||||
label: '密码设置',
|
||||
children: (
|
||||
<Password
|
||||
password={password || {}}
|
||||
setValue={(path, value) =>
|
||||
setValue(`Password.${path}`, value)
|
||||
}
|
||||
setValues={(value) => {
|
||||
setValues({
|
||||
Password: value
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
></Tabs>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -38,9 +38,8 @@ export default OakComponent({
|
|||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig: PwdConfig = applicationPassports.find((ele: EntityDict['applicationPassport']['Schema']) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@ export default OakComponent({
|
|||
lifetimes: {
|
||||
async ready() {
|
||||
this.features.token.getToken();
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig: PwdConfig = applicationPassports.find((ele: EntityDict['applicationPassport']['Schema']) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
this.setState({
|
||||
mode,
|
||||
|
|
|
|||
|
|
@ -90,9 +90,8 @@ export default OakComponent({
|
|||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
const application = this.features.application.getApplication();
|
||||
const { result: applicationPassports } = await this.features.cache.exec('getApplicationPassports', { applicationId: application.id });
|
||||
const passwordConfig: PwdConfig = applicationPassports.find((ele: EntityDict['applicationPassport']['Schema']) => ele.passport.type === 'password')?.passport.config;
|
||||
const system = this.features.application.getApplication().system;
|
||||
const passwordConfig = system?.config.Password;
|
||||
const mode = passwordConfig?.mode ?? 'all';
|
||||
const pwdMin = passwordConfig?.min ?? 8;
|
||||
const pwdMax = passwordConfig?.max ?? 24;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ export type LocalCosConfig = {
|
|||
};
|
||||
|
||||
// S3/Minio 的区域类型(可以根据实际需要扩展)
|
||||
export type S3Zone =
|
||||
export type S3Zone =
|
||||
| 'us-east-1'
|
||||
| 'us-west-1'
|
||||
| 'us-west-2'
|
||||
|
|
@ -185,6 +185,15 @@ export type EmailConfig = {
|
|||
secure?: boolean; //是否ssl
|
||||
};
|
||||
|
||||
export type PasswordConfig = {
|
||||
mode?: 'all' | 'plain' | 'sha1' //密码存储模式,默认为all
|
||||
min?: number; //位数最小值,默认为8
|
||||
max?: number; //位数最大值,默认为24
|
||||
verify?: boolean; //开启正则校验,默认不开启
|
||||
regexs?: string[];
|
||||
tip?: string; //登录提示语
|
||||
};
|
||||
|
||||
export type QrCodeType = 'wechatMpDomainUrl' | 'wechatMpWxaCode' | 'wechatPublic' | 'wechatPublicForMp' | 'webForWechatPublic';
|
||||
|
||||
export type Config = {
|
||||
|
|
@ -236,7 +245,8 @@ export type Config = {
|
|||
type?: 'password', // 采用密码作为第一安全元素
|
||||
level?: 'weak' | 'medium' | 'strong'; // 强度
|
||||
passwordVerifyGap?: number; // 在密码验证后的多长时间内认为是安全的,可以做敏感动作
|
||||
}
|
||||
};
|
||||
Password?: PasswordConfig;
|
||||
};
|
||||
|
||||
export type AccountOrigin = 'ali' | 'tencent' | 'qiniu' | 'amap' | 'ctyun' | 'local' | 's3';
|
||||
|
|
|
|||
Loading…
Reference in New Issue