From 36a99648991e8f513445523383f0929f2f9b7598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=87=AA=E5=B8=A6=E5=A4=A7=E4=BD=AC=E6=B0=94=E5=9C=BA?= <188633308@qq.com> Date: Fri, 2 Jul 2021 19:00:01 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E9=AA=8C=E8=AF=81=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E5=BC=BA=E5=BA=A6,=E5=B9=B6=E4=BF=AE=E6=94=B9=E5=AF=86?= =?UTF-8?q?=E7=A0=81,=E5=9C=A8debug=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E4=B8=8D=E9=9C=80=E8=A6=81=E6=AD=A3=E7=A1=AE=E5=AF=86?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Api/Ewide.Core/Ewide.Core.xml | 58 +++++---- Api/Ewide.Core/Service/Auth/AuthService.cs | 103 +++++++++++++--- Api/Ewide.Core/Service/Auth/Dto/LoginInput.cs | 23 +++- .../Service/Auth/Dto/LoginOutput.cs | 11 +- Api/Ewide.Core/Service/Auth/IAuthService.cs | 4 +- Api/Ewide.Core/applicationconfig.json | 5 + .../common/api/requests/sys/loginManage.js | 4 + web-react/src/views/login/index.jsx | 116 +++++++++++++++++- 8 files changed, 274 insertions(+), 50 deletions(-) diff --git a/Api/Ewide.Core/Ewide.Core.xml b/Api/Ewide.Core/Ewide.Core.xml index 712fedc..c72f463 100644 --- a/Api/Ewide.Core/Ewide.Core.xml +++ b/Api/Ewide.Core/Ewide.Core.xml @@ -3228,122 +3228,132 @@ 123456 - + + + 新密码 + + + + + 确认密码 + + + 用户登录输出参数 - + 主键 - + 账号 - + 密码安全级别 - + 昵称 - + 姓名 - + 头像 - + 生日 - + 性别(字典 1男 2女) - + 邮箱 - + 手机 - + 电话 - + 管理员类型(0超级管理员 1非管理员) - + 最后登陆IP - + 最后登陆时间 - + 最后登陆地址 - + 最后登陆所用浏览器 - + 最后登陆所用系统 - + 员工信息 - + 具备应用信息 - + 角色信息 - + 权限信息 - + 登录菜单信息---AntDesign版本菜单 - + 数据范围(机构)信息 diff --git a/Api/Ewide.Core/Service/Auth/AuthService.cs b/Api/Ewide.Core/Service/Auth/AuthService.cs index 0571c5f..b1e7d0f 100644 --- a/Api/Ewide.Core/Service/Auth/AuthService.cs +++ b/Api/Ewide.Core/Service/Auth/AuthService.cs @@ -14,6 +14,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using UAParser; @@ -68,20 +69,90 @@ namespace Ewide.Core.Service /// [HttpPost("/login")] [AllowAnonymous] - public async Task LoginAsync([Required] LoginInput input) + public async Task LoginAsync([Required] LoginInput input) { - string pwd = RSAHandler.RSADecrypt(input.Password); - // 获取加密后的密码 - var encryptPasswod = MD5Encryption.Encrypt(pwd); + var password = RSAHandler.RSADecrypt(input.Password); + var user = await GetUser(input); + +#if !DEBUG + // 验证密码强度 + var pattern = App.Configuration.GetSection("SimplePassword:Pattern").Value; + if (!Regex.Match(password, pattern).Success) + { + return new LoginOutput + { + Passed = false, + Pattern = pattern, + Descriptions = App.Configuration.GetSection("SimplePassword:Descriptions").Value + }; + } +#endif + + return new LoginOutput + { + Passed = true, + Token = await HandlerLoginAsync(user) + }; + } + + [HttpPost("/loginPass")] + [AllowAnonymous] + public async Task LoginPassAsync([Required] LoginPassInput input) + { + var user = await GetUser(input); + + var newPassword = RSAHandler.RSADecrypt(input.NewPassword); + // 验证新密码强度 + var pattern = App.Configuration.GetSection("SimplePassword:Pattern").Value; + if (!Regex.Match(newPassword, pattern).Success) + { + return new LoginOutput + { + Passed = false, + Pattern = pattern, + Descriptions = App.Configuration.GetSection("SimplePassword:Descriptions").Value + }; + } + + newPassword = MD5Encryption.Encrypt(newPassword); + if (newPassword.Equals(user.Password)) + throw Oops.Oh(ErrorCode.D10041); + + user.Password = newPassword; + + return new LoginOutput + { + Passed = true, + Token = await HandlerLoginAsync(user) + }; + + } + + private async Task GetUser(LoginInput input) + { + var password = RSAHandler.RSADecrypt(input.Password); + // 获取加密后的密码 + var encryptPasswod = MD5Encryption.Encrypt(password); + +#if DEBUG + var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Account.Equals(input.Account)); +#else // 判断用户名和密码是否正确 var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Account.Equals(input.Account) && u.Password.Equals(encryptPasswod)); _ = user ?? throw Oops.Oh(ErrorCode.D1000); +#endif // 验证账号是否被冻结 if (user.Status == CommonStatus.DISABLE) throw Oops.Oh(ErrorCode.D1017); + return user; + } + + + private async Task HandlerLoginAsync(SysUser user) + { // 生成Token令牌 //var accessToken = await _jwtBearerManager.CreateTokenAdmin(user); var accessToken = JWTEncryption.Encrypt(new Dictionary @@ -102,38 +173,40 @@ namespace Ewide.Core.Service _httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken; // 增加登录日志 - var loginOutput = user.Adapt(); + var loginUserOutput = user.Adapt(); var clent = Parser.GetDefault().Parse(App.GetService().HttpContext.Request.Headers["User-Agent"]); - loginOutput.LastLoginBrowser = clent.UA.Family + clent.UA.Major; - loginOutput.LastLoginOs = clent.OS.Family + clent.OS.Major; + loginUserOutput.LastLoginBrowser = clent.UA.Family + clent.UA.Major; + loginUserOutput.LastLoginOs = clent.OS.Family + clent.OS.Major; await new SysLogVis { Name = "登录", Success = true, Message = "登录成功", - Ip = loginOutput.LastLoginIp, - Browser = loginOutput.LastLoginBrowser, - Os = loginOutput.LastLoginOs, + Ip = loginUserOutput.LastLoginIp, + Browser = loginUserOutput.LastLoginBrowser, + Os = loginUserOutput.LastLoginOs, VisType = 1, - VisTime = loginOutput.LastLoginTime, - Account = loginOutput.Account + VisTime = loginUserOutput.LastLoginTime, + Account = loginUserOutput.Account }.InsertAsync(); return accessToken; + } + /// /// 获取当前登录用户信息 /// /// [HttpGet("/getLoginUser")] - public async Task GetLoginUserAsync() + public async Task GetLoginUserAsync() { var user = _userManager.User; var userId = user.Id; var httpContext = App.GetService().HttpContext; - var loginOutput = user.Adapt(); + var loginOutput = user.Adapt(); // 隐藏手机号/邮箱中间几位 loginOutput.Phone = String.IsNullOrEmpty(loginOutput.Phone) ? loginOutput.Phone @@ -197,7 +270,7 @@ namespace Ewide.Core.Service var userId = user.Id; var httpContext = App.GetService().HttpContext; - var loginOutput = user.Adapt(); + var loginOutput = user.Adapt(); var ip = httpContext.Request.Headers["X-Real-IP"]; diff --git a/Api/Ewide.Core/Service/Auth/Dto/LoginInput.cs b/Api/Ewide.Core/Service/Auth/Dto/LoginInput.cs index e57dbb7..2bd2803 100644 --- a/Api/Ewide.Core/Service/Auth/Dto/LoginInput.cs +++ b/Api/Ewide.Core/Service/Auth/Dto/LoginInput.cs @@ -1,4 +1,5 @@ -using Furion.DependencyInjection; +using Furion; +using Furion.DependencyInjection; using System.ComponentModel.DataAnnotations; namespace Ewide.Core.Service @@ -14,13 +15,29 @@ namespace Ewide.Core.Service /// /// superAdmin [Required(ErrorMessage = "用户名不能为空"), MinLength(3, ErrorMessage = "用户名不能少于3位字符")] - public string Account { get; set; } + public virtual string Account { get; set; } /// /// 密码 /// /// 123456 [Required(ErrorMessage = "密码不能为空"), MinLength(5, ErrorMessage = "密码不能少于5位字符")] - public string Password { get; set; } + public virtual string Password { get; set; } + } + + [SkipScan] + public class LoginPassInput : LoginInput + { + /// + /// 新密码 + /// + [Required(ErrorMessage = "新密码不能为空")] + public string NewPassword { get; set; } + + /// + /// 确认密码 + /// + [Required(ErrorMessage = "确认密码不能为空"), Compare(nameof(NewPassword), ErrorMessage = "两次密码不一致")] + public string Confirm { get; set; } } } diff --git a/Api/Ewide.Core/Service/Auth/Dto/LoginOutput.cs b/Api/Ewide.Core/Service/Auth/Dto/LoginOutput.cs index e066ed6..3fb0bb8 100644 --- a/Api/Ewide.Core/Service/Auth/Dto/LoginOutput.cs +++ b/Api/Ewide.Core/Service/Auth/Dto/LoginOutput.cs @@ -4,11 +4,20 @@ using System.Collections.Generic; namespace Ewide.Core.Service { + [SkipScan] + public class LoginOutput + { + public bool Passed { get; set; } + public string Pattern { get; set; } + public string Descriptions { get; set; } + public string Token { get; set; } + } + /// /// 用户登录输出参数 /// [SkipScan] - public class LoginOutput + public class LoginUserOutput { /// /// 主键 diff --git a/Api/Ewide.Core/Service/Auth/IAuthService.cs b/Api/Ewide.Core/Service/Auth/IAuthService.cs index 5c63d70..395a3d6 100644 --- a/Api/Ewide.Core/Service/Auth/IAuthService.cs +++ b/Api/Ewide.Core/Service/Auth/IAuthService.cs @@ -7,8 +7,8 @@ namespace Ewide.Core.Service { Task GetCaptcha(); Task GetCaptchaOpen(); - Task GetLoginUserAsync(); - Task LoginAsync([Required] LoginInput input); + Task GetLoginUserAsync(); + Task LoginAsync([Required] LoginInput input); Task LogoutAsync(); Task VerificationCode(ClickWordCaptchaInput input); } diff --git a/Api/Ewide.Core/applicationconfig.json b/Api/Ewide.Core/applicationconfig.json index 9008b08..3ae16a9 100644 --- a/Api/Ewide.Core/applicationconfig.json +++ b/Api/Ewide.Core/applicationconfig.json @@ -102,5 +102,10 @@ "sysNotice:unread", "sysNotice:detail" ] + }, + + "SimplePassword": { + "Pattern": "(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]){8,}", + "Descriptions": "密码中必须包含大小字母、数字、特称字符,至少8个字符" } } \ No newline at end of file diff --git a/web-react/src/common/api/requests/sys/loginManage.js b/web-react/src/common/api/requests/sys/loginManage.js index 8d969e3..216a8e4 100644 --- a/web-react/src/common/api/requests/sys/loginManage.js +++ b/web-react/src/common/api/requests/sys/loginManage.js @@ -3,6 +3,10 @@ const urls = { * 登录 */ login: ['/login', 'post'], + /** + * 登录时修改密码 + */ + loginPass: ['/loginPass', 'post'], /** * 登出 */ diff --git a/web-react/src/views/login/index.jsx b/web-react/src/views/login/index.jsx index d7290aa..ef7dfa2 100644 --- a/web-react/src/views/login/index.jsx +++ b/web-react/src/views/login/index.jsx @@ -1,5 +1,5 @@ import React, { Component } from 'react' -import { Button, Form, Input, message as Message } from 'antd' +import { Alert, Button, Form, Input, message as Message, Modal } from 'antd' import Container from 'components/container' import { encryptByRSA } from 'util/rsa' import { RSA_PUBLIC_KEY } from 'util/global' @@ -14,6 +14,10 @@ export default class index extends Component { focusPassword: false, btnDisabled: true, + + pattern: '', + descriptions: '', + visible: false, } backgroundImage = require(`assets/image/login-bg-0${Math.floor(Math.random() * 4)}.jpg`) @@ -33,9 +37,19 @@ export default class index extends Component { api.login({ account, password }) .then(({ success, data, message }) => { if (success) { - token.value = data - Message.success('登录成功') - this.props.history.replace('/') + const { passed, pattern, descriptions, token } = data + // 简单密码需要更改 + if (!passed) { + this.setState({ + visible: true, + loading: false, + btnDisabled: true, + pattern, + descriptions, + }) + } else { + this.onLoginSuccess(token) + } } else { this.setState({ loading: false }) Message.error(message) @@ -49,8 +63,52 @@ export default class index extends Component { }) } + onLoginPass = values => { + this.setState({ loading: true }) + const account = this.form.current.getFieldValue('account') + let { password, newPassword } = values + password = encryptByRSA(password, RSA_PUBLIC_KEY) + newPassword = encryptByRSA(newPassword, RSA_PUBLIC_KEY) + const confirm = newPassword // 前端验证两次密码即可.不需要加密 + + api.loginPass({ account, password, newPassword, confirm }) + .then(({ success, data, message }) => { + if (success) { + const { passed, pattern, descriptions, token } = data + // 简单密码需要更改 + if (!passed) { + this.setState({ + visible: true, + loading: false, + btnDisabled: true, + pattern, + descriptions, + }) + } else { + this.onLoginSuccess(token) + } + } else { + this.setState({ loading: false }) + Message.error(message) + } + }) + .catch(({ message }) => { + if (typeof message === 'object' && message[0]) { + Message.error(message[0].messages[0]) + } + this.setState({ loading: false }) + }) + } + + onLoginSuccess(jwtToken) { + token.value = jwtToken + Message.success('登录成功') + this.props.history.replace('/') + } + render() { - const { loading, focusUser, focusPassword, btnDisabled } = this.state + const { loading, focusUser, focusPassword, btnDisabled, visible, pattern, descriptions } = + this.state return (
@@ -121,6 +179,54 @@ export default class index extends Component {
+ + +
+
+
+ + + + + + + ({ + validator(_, value) { + if (!value || getFieldValue('newPassword') === value) { + return Promise.resolve() + } + return Promise.reject(new Error('确认新密码不匹配')) + }, + }), + ]} + name="confirm" + > + + +
+ + + +
+
) }