diff --git a/Api/Ewide.Core/Ewide.Core.xml b/Api/Ewide.Core/Ewide.Core.xml index c89a9df..bb4748b 100644 --- a/Api/Ewide.Core/Ewide.Core.xml +++ b/Api/Ewide.Core/Ewide.Core.xml @@ -7189,6 +7189,13 @@ 检验验证码并且绑定 + + + 获取密码强度配置 + + + + 发送验证码间隔时间(秒) @@ -7271,6 +7278,13 @@ + + + 检测是否重复 + + + + 邮箱类 diff --git a/Api/Ewide.Core/Service/User/Dto/UserInput.cs b/Api/Ewide.Core/Service/User/Dto/UserInput.cs index a096e4c..8b0c679 100644 --- a/Api/Ewide.Core/Service/User/Dto/UserInput.cs +++ b/Api/Ewide.Core/Service/User/Dto/UserInput.cs @@ -128,7 +128,6 @@ namespace Ewide.Core.Service /// 新密码 /// [Required(ErrorMessage = "新密码不能为空")] - [StringLength(32, MinimumLength = 5, ErrorMessage = "密码需要大于5个字符")] public string NewPassword { get; set; } /// diff --git a/Api/Ewide.Core/Service/User/ISysUserService.cs b/Api/Ewide.Core/Service/User/ISysUserService.cs index a021e77..a0c9cda 100644 --- a/Api/Ewide.Core/Service/User/ISysUserService.cs +++ b/Api/Ewide.Core/Service/User/ISysUserService.cs @@ -29,7 +29,7 @@ namespace Ewide.Core.Service Task SendCode(Usermailphone input); Task CheckBindcode(Usermailphone input); - + Task GetPwdRule(); Task GetOrgUserTree(OrgUserInput input); } } \ No newline at end of file diff --git a/Api/Ewide.Core/Service/User/SysUserService.cs b/Api/Ewide.Core/Service/User/SysUserService.cs index d8c0c65..72d56f2 100644 --- a/Api/Ewide.Core/Service/User/SysUserService.cs +++ b/Api/Ewide.Core/Service/User/SysUserService.cs @@ -1,6 +1,7 @@ using Ewide.Core.Service.Role; using Ewide.Core.Service.User.Dto; using Ewide.Core.Util; +using Furion; using Furion.DatabaseAccessor; using Furion.DatabaseAccessor.Extensions; using Furion.DataEncryption; @@ -312,11 +313,26 @@ namespace Ewide.Core.Service public async Task UpdateUserPwd(ChangePasswordUserInput input) { var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == _userManager.UserId); - if (MD5Encryption.Encrypt(input.Password) != user.Password) - throw Oops.Oh(ErrorCode.D1004); - if (MD5Encryption.Encrypt(input.NewPassword).Equals(user.Password)) + var Password = RSAHandler.RSADecrypt(input.Password); + Password = MD5Encryption.Encrypt(Password); + if (Password != user.Password) + { + throw Oops.Oh("旧密码不正确"); + } + var newPassword = RSAHandler.RSADecrypt(input.NewPassword); + // 验证新密码强度 + var pattern = App.Configuration.GetSection("SimplePassword:Pattern").Value; + if (!Regex.Match(newPassword, pattern).Success) + { + throw Oops.Oh("新密码强度不符合规则"); + } + + newPassword = MD5Encryption.Encrypt(newPassword); + if (newPassword.Equals(user.Password)) throw Oops.Oh(ErrorCode.D10041); - user.Password = MD5Encryption.Encrypt(input.NewPassword); + + user.Password = newPassword; + } /// @@ -467,7 +483,7 @@ namespace Ewide.Core.Service var Mailcode_Key = "ewide_mailcode"; var Regex_phone = @"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$"; var Regex_Email = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"; - CodeHelper ch = new CodeHelper(_iMemoryCache); + CodeHelper ch = new CodeHelper(_iMemoryCache, _sysUserRep, _userManager); //Type为1时,给原手机号发送验证码 if (input.Type == 1) { @@ -484,7 +500,7 @@ namespace Ewide.Core.Service //Type为2时,给原邮箱发送验证码 else if (input.Type == 2) { - if (new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").IsMatch(_userManager.User.Email)) + if (new Regex(Regex_Email).IsMatch(_userManager.User.Email)) { try { @@ -500,6 +516,7 @@ namespace Ewide.Core.Service //Type为null时,则发验证码 else { + await ch.CheckRepeat(input.Target); //通过正则判断绑定类型 if (new Regex(Regex_phone).IsMatch(input.Target)) { @@ -542,7 +559,7 @@ namespace Ewide.Core.Service var Regex_phone = @"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$"; var Regex_Email = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"; var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == _userManager.UserId); - CodeHelper ch = new CodeHelper(_iMemoryCache); + CodeHelper ch = new CodeHelper(_iMemoryCache, _sysUserRep,_userManager); if (input.Type == 1) { if (ch.Checkcode(_userManager.User.Phone, input.Orgcode, Orgcode_Key)) @@ -655,6 +672,23 @@ namespace Ewide.Core.Service } } + /// + /// 获取密码强度配置 + /// + /// + /// + [HttpPost("/sysUser/getPwdRule")] + public async Task GetPwdRule() + { + return new LoginOutput + { + Pattern = App.Configuration.GetSection("SimplePassword:Pattern").Value, + Descriptions = App.Configuration.GetSection("SimplePassword:Descriptions").Value + }; + } + + + [HttpPost("/sysUser/GetOrgUserTree")] public async Task GetOrgUserTree(OrgUserInput input) { diff --git a/Api/Ewide.Core/Util/CodeHelper.cs b/Api/Ewide.Core/Util/CodeHelper.cs index 9ae5256..00fe3a4 100644 --- a/Api/Ewide.Core/Util/CodeHelper.cs +++ b/Api/Ewide.Core/Util/CodeHelper.cs @@ -2,7 +2,9 @@ using Aliyun.Acs.Core.Exceptions; using Aliyun.Acs.Core.Profile; using Furion; +using Furion.DatabaseAccessor; using Furion.FriendlyException; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -19,9 +21,17 @@ namespace Ewide.Core.Util public class CodeHelper { private readonly IMemoryCache _IMemoryCache; - public CodeHelper(IMemoryCache IMemoryCache) - { + private readonly IRepository _sysUserRep; // 用户表仓储 + private readonly IUserManager _userManager; + + public CodeHelper( + IMemoryCache IMemoryCache, + IRepository sysUserRep, + IUserManager userManager + ){ _IMemoryCache = IMemoryCache; + _sysUserRep = sysUserRep; + _userManager = userManager; } public static string Aliyun_AccessKey = App.Configuration["SmsHelper:Aliyun_AccessKey"]; public static string Aliyun_AccessSecret = App.Configuration["SmsHelper:Aliyun_AccessSecret"]; @@ -246,7 +256,25 @@ namespace Ewide.Core.Util throw Oops.Oh(ErrorCode.xg1100); } } - - + + /// + /// 检测是否重复 + /// + /// + /// + public async Task CheckRepeat(string Target) + { + var Regex_phone = @"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$"; + var Regex_Email = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"; + if(new Regex(Regex_phone).IsMatch(Target)){ + var isExist = await _sysUserRep.DetachedEntities.AnyAsync(u => (u.Id != _userManager.UserId ) && (u.Account == Target || u.Phone == Target)); + if (isExist) throw Oops.Oh("手机号与他人账号或者手机号重复"); + }else if(new Regex(Regex_Email).IsMatch(Target)) + { + var isExist3 = await _sysUserRep.DetachedEntities.AnyAsync(u => (u.Id != _userManager.UserId) && (u.Account == Target || u.Email == Target)); + if (isExist3) throw Oops.Oh("邮箱与他人账号或者邮箱重复"); + } + return true; + } } } diff --git a/web-react/src/common/api/requests/sys/userManage.js b/web-react/src/common/api/requests/sys/userManage.js index 2d9a478..8307459 100644 --- a/web-react/src/common/api/requests/sys/userManage.js +++ b/web-react/src/common/api/requests/sys/userManage.js @@ -85,6 +85,11 @@ const urls = { */ sysUserCheckBindcode: ['/sysUser/checkBindcode', 'post'], + /** + * 获取密码验证配置 + */ + getPwdRule: ['/sysUser/getPwdRule', 'post'], + } export default urls \ No newline at end of file diff --git a/web-react/src/pages/system/account/setting/satety/index.jsx b/web-react/src/pages/system/account/setting/satety/index.jsx index e6ab368..d5f276b 100644 --- a/web-react/src/pages/system/account/setting/satety/index.jsx +++ b/web-react/src/pages/system/account/setting/satety/index.jsx @@ -115,9 +115,9 @@ export default class form extends Component { )} /> - - - + {/* */} + + {/* */} diff --git a/web-react/src/pages/system/account/setting/satety/password.jsx b/web-react/src/pages/system/account/setting/satety/password.jsx index 6e0c9db..b37eb86 100644 --- a/web-react/src/pages/system/account/setting/satety/password.jsx +++ b/web-react/src/pages/system/account/setting/satety/password.jsx @@ -1,24 +1,68 @@ import React, { Component } from 'react' -import { Form, Input } from 'antd' +import { Form, Input, message as Message, Modal } from 'antd' +import { api } from 'common/api' +import { RSA_PUBLIC_KEY } from 'util/global' +import { cloneDeep } from 'lodash' +import { Button } from 'antd/lib/radio' +import { encryptByRSA } from 'util/rsa' + +const initData = { + exist: false, + pattern: '', + descriptions: '', + visible: false, +} export default class form extends Component { - state = { - // 加载状态 - exist: false, - } + state = cloneDeep(initData) // 表单实例 form = React.createRef() // 初始化数据 record = {} + open = () => { + this.setState({ visible: true }) + } + /** * mount后回调 */ componentDidMount() { this.props.created && this.props.created(this) + api.getPwdRule({}).then(({ success, data, message }) => { + if (success) { + const { pattern, descriptions } = data + this.setState({ + pattern, + descriptions, + }) + } else { + Message.Error(message) + } + }) } + updatePwd(values) { + let { password, newPassword } = values.current.getFieldsValue() + password = encryptByRSA(password, RSA_PUBLIC_KEY) + newPassword = encryptByRSA(newPassword, RSA_PUBLIC_KEY) + const confirm = newPassword + api.sysUserUpdatePwd({ password, newPassword, confirm }).then( + ({ success, data, message }) => { + if (success) { + Message.success('密码修改完成') + this.close() + } else { + Message.warn(message) + } + } + ) + } + + close() { + this.setState(cloneDeep(initData)) + } /** * 填充数据 * 可以在设置this.record之后对其作出数据结构调整 @@ -46,42 +90,56 @@ export default class form extends Component { } render() { + const { pattern, descriptions, visible } = this.state return ( -
-
- - - - - - - ({ - validator(_, value) { - if (!value || getFieldValue('newPassword') === value) { - return Promise.resolve() - } - return Promise.reject(new Error('确认新密码不匹配')) - }, - }), - ]} - name="confirm" - > - - -
-
+ this.close()} + onOk={() => this.updatePwd(this.form)} + visible={visible} + className="yo-modal-form" + title="更新密码" + > +
+
+ + + + + + + ({ + validator(_, value) { + if (!value || getFieldValue('newPassword') === value) { + return Promise.resolve() + } + return Promise.reject(new Error('确认新密码不匹配')) + }, + }), + ]} + name="confirm" + > + + +
+
+
) } }