From d7629763efe27c0643b6756069a5c88c5c1c9982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Thu, 3 Oct 2024 01:10:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=89=BE=E5=9B=9E?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E5=8A=9F=E8=83=BD=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/Account/RetrievePasswordDto.cs | 24 +++ .../Services/AccountService.cs | 85 ++++++-- .../Caches/CaptchaPhoneCacheItem.cs | 9 +- .../Enums/ValidationPhoneTypeEnum.cs | 13 ++ .../Managers/AccountManager.cs | 6 +- .../Operlog/OperationLogEntity.cs | 4 +- Yi.Bbs.Vue3/src/assets/styles/login.css | 8 +- Yi.Bbs.Vue3/src/hooks/useAuths.js | 2 +- Yi.Bbs.Vue3/src/layout/LoginLayout.vue | 43 ++++ Yi.Bbs.Vue3/src/router/index.js | 10 +- .../src/views/login/ForgotPassword.vue | 11 + Yi.Bbs.Vue3/src/views/login/index.vue | 191 +----------------- Yi.Bbs.Vue3/src/views/login/register.vue | 178 ++++++++++++++++ 13 files changed, 362 insertions(+), 222 deletions(-) create mode 100644 Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Account/RetrievePasswordDto.cs create mode 100644 Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Enums/ValidationPhoneTypeEnum.cs create mode 100644 Yi.Bbs.Vue3/src/views/login/ForgotPassword.vue create mode 100644 Yi.Bbs.Vue3/src/views/login/register.vue diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Account/RetrievePasswordDto.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Account/RetrievePasswordDto.cs new file mode 100644 index 00000000..a7971069 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Account/RetrievePasswordDto.cs @@ -0,0 +1,24 @@ +namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Account; + +public class RetrievePasswordDto +{ + /// + /// 密码 + /// + public string Password { get; set; } + + /// + /// 唯一标识码 + /// + public string? Uuid { get; set; } + + /// + /// 电话 + /// + public long Phone { get; set; } + + /// + /// 验证码 + /// + public string? Code { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs index 07600dab..8676435c 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs @@ -27,6 +27,7 @@ using Yi.Framework.Rbac.Domain.Repositories; using Yi.Framework.Rbac.Domain.Shared.Caches; using Yi.Framework.Rbac.Domain.Shared.Consts; using Yi.Framework.Rbac.Domain.Shared.Dtos; +using Yi.Framework.Rbac.Domain.Shared.Enums; using Yi.Framework.Rbac.Domain.Shared.Etos; using Yi.Framework.Rbac.Domain.Shared.Options; using Yi.Framework.SqlSugarCore.Abstractions; @@ -44,6 +45,7 @@ namespace Yi.Framework.Rbac.Application.Services private IDistributedCache _userCache; private UserManager _userManager; private IHttpContextAccessor _httpContextAccessor; + public AccountService(IUserRepository userRepository, ICurrentUser currentUser, IAccountManager accountManager, @@ -127,7 +129,7 @@ namespace Yi.Framework.Rbac.Application.Services loginEto.UserId = userInfo.User.Id; await LocalEventBus.PublishAsync(loginEto); } - + return new { Token = accessToken, RefreshToken = refreshToken }; } @@ -178,14 +180,35 @@ namespace Yi.Framework.Rbac.Application.Services /// - /// 注册 手机验证码 + /// 手机验证码-注册 + /// + /// + /// + [HttpPost("captcha-phone")] + [AllowAnonymous] + public async Task PostCaptchaPhoneForRegisterAsync(PhoneCaptchaImageDto input) + { + return await PostCaptchaPhoneAsync(ValidationPhoneTypeEnum.Register, input); + } + /// + /// 手机验证码-找回密码 + /// + /// + /// + [HttpPost("captcha-phone/repassword")] + public async Task PostCaptchaPhoneForRetrievePasswordAsync(PhoneCaptchaImageDto input) + { + return await PostCaptchaPhoneAsync(ValidationPhoneTypeEnum.RetrievePassword, input); + } + /// + /// 手机验证码 /// /// - [AllowAnonymous] - public async Task PostCaptchaPhone(PhoneCaptchaImageDto input) + private async Task PostCaptchaPhoneAsync(ValidationPhoneTypeEnum validationPhoneType, + PhoneCaptchaImageDto input) { await ValidationPhone(input.Phone); - var value = await _phoneCache.GetAsync(new CaptchaPhoneCacheKey(input.Phone)); + var value = await _phoneCache.GetAsync(new CaptchaPhoneCacheKey(validationPhoneType, input.Phone)); //防止暴刷 if (value is not null) @@ -200,7 +223,8 @@ namespace Yi.Framework.Rbac.Application.Services var uuid = Guid.NewGuid(); await _aliyunManger.SendSmsAsync(input.Phone, code); - await _phoneCache.SetAsync(new CaptchaPhoneCacheKey(input.Phone), new CaptchaPhoneCacheItem(code), + await _phoneCache.SetAsync(new CaptchaPhoneCacheKey(ValidationPhoneTypeEnum.Register, input.Phone), + new CaptchaPhoneCacheItem(code), new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(10) }); return new { @@ -211,19 +235,44 @@ namespace Yi.Framework.Rbac.Application.Services /// /// 校验电话验证码,需要与电话号码绑定 /// - private async Task ValidationPhoneCaptchaAsync(RegisterDto input) + private async Task ValidationPhoneCaptchaAsync(ValidationPhoneTypeEnum validationPhoneType, long phone, + string code) { - var item = await _phoneCache.GetAsync(new CaptchaPhoneCacheKey(input.Phone.ToString())); - if (item is not null && item.Code.Equals($"{input.Code}")) + var item = await _phoneCache.GetAsync(new CaptchaPhoneCacheKey(validationPhoneType, phone.ToString())); + if (item is not null && item.Code.Equals($"{code}")) { //成功,需要清空 - await _phoneCache.RemoveAsync(new CaptchaPhoneCacheKey(input.Phone.ToString())); + await _phoneCache.RemoveAsync(new CaptchaPhoneCacheKey(validationPhoneType, code.ToString())); return; } throw new UserFriendlyException("验证码错误"); } + /// + /// 找回密码 + /// + /// + [AllowAnonymous] + [UnitOfWork] + public async Task PostRetrievePasswordAsync(RetrievePasswordDto input) + { + if (_rbacOptions.EnableCaptcha) + { + //校验验证码,根据电话号码获取 value,比对验证码已经uuid + await ValidationPhoneCaptchaAsync(ValidationPhoneTypeEnum.RetrievePassword, input.Phone, input.Code); + } + + var entity = await _userRepository.GetFirstAsync(x => x.Phone == input.Phone); + if (entity is null) + { + throw new UserFriendlyException("该手机号码未注册"); + } + + await _accountManager.RestPasswordAsync(entity.Id, input.Password); + } + + /// /// 注册,需要验证码通过 /// @@ -241,16 +290,16 @@ namespace Yi.Framework.Rbac.Application.Services if (_rbacOptions.EnableCaptcha) { //校验验证码,根据电话号码获取 value,比对验证码已经uuid - await ValidationPhoneCaptchaAsync(input); + await ValidationPhoneCaptchaAsync(ValidationPhoneTypeEnum.Register, input.Phone, input.Code); } //注册领域逻辑 - await _accountManager.RegisterAsync(input.UserName, input.Password, input.Phone,input.Nick); + await _accountManager.RegisterAsync(input.UserName, input.Password, input.Phone, input.Nick); } /// - /// 查询已登录的账户信息,已缓存 + /// 查询已登录的账户信息 /// /// [Route("account")] @@ -270,9 +319,6 @@ namespace Yi.Framework.Rbac.Application.Services } - - - /// /// 获取当前登录用户的前端路由 /// 支持ruoyi/pure @@ -280,7 +326,7 @@ namespace Yi.Framework.Rbac.Application.Services /// [Authorize] [Route("account/Vue3Router/{routerType?}")] - public async Task GetVue3Router([FromRoute]string? routerType) + public async Task GetVue3Router([FromRoute] string? routerType) { var userId = _currentUser.Id; if (_currentUser.Id is null) @@ -298,18 +344,19 @@ namespace Yi.Framework.Rbac.Application.Services } object output = null; - if (routerType is null ||routerType=="ruoyi") + if (routerType is null || routerType == "ruoyi") { //将后端菜单转换成前端路由,组件级别需要过滤 output = ObjectMapper.Map, List>(menus).Vue3RuoYiRouterBuild(); } - else if (routerType =="pure") + else if (routerType == "pure") { //将后端菜单转换成前端路由,组件级别需要过滤 output = ObjectMapper.Map, List>(menus).Vue3PureRouterBuild(); } + return output; } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs index 5ec63192..a66614e2 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Yi.Framework.Rbac.Domain.Shared.Enums; namespace Yi.Framework.Rbac.Domain.Shared.Caches { @@ -14,13 +15,15 @@ namespace Yi.Framework.Rbac.Domain.Shared.Caches public class CaptchaPhoneCacheKey { - public CaptchaPhoneCacheKey(string phone) { Phone = phone; } - + public CaptchaPhoneCacheKey(ValidationPhoneTypeEnum validationPhoneType,string phone) { Phone = phone; + ValidationPhoneType = validationPhoneType; + } + public ValidationPhoneTypeEnum ValidationPhoneType { get; set; } public string Phone { get; set; } public override string ToString() { - return $"Phone:{Phone}"; + return $"Phone:{ValidationPhoneType.ToString()}:{Phone}"; } } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Enums/ValidationPhoneTypeEnum.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Enums/ValidationPhoneTypeEnum.cs new file mode 100644 index 00000000..0446fb49 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Enums/ValidationPhoneTypeEnum.cs @@ -0,0 +1,13 @@ +namespace Yi.Framework.Rbac.Domain.Shared.Enums; + +public enum ValidationPhoneTypeEnum +{ + /// + /// 注册 + /// + Register, + /// + /// 忘记密码 + /// + RetrievePassword +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs index 7aa1068c..7051f71c 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs @@ -180,6 +180,8 @@ namespace Yi.Framework.Rbac.Domain.Managers } return false; } + + /// /// 令牌转换 @@ -250,7 +252,7 @@ namespace Yi.Framework.Rbac.Domain.Managers } /// - /// 重置密码 + /// 重置密码,也可以是找回密码 /// /// /// @@ -258,7 +260,6 @@ namespace Yi.Framework.Rbac.Domain.Managers public async Task RestPasswordAsync(Guid userId, string password) { var user = await _repository.GetByIdAsync(userId); - // EntityHelper.TrySetId(user, () => GuidGenerator.Create(), true); user.EncryPassword.Password = password; user.BuildPassword(); return await _repository.UpdateAsync(user); @@ -276,7 +277,6 @@ namespace Yi.Framework.Rbac.Domain.Managers var user = new UserAggregateRoot(userName, password, phone,nick); await _userManager.CreateAsync(user); await _userManager.SetDefautRoleAsync(user.Id); - } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Operlog/OperationLogEntity.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Operlog/OperationLogEntity.cs index fae49aeb..e3394a8f 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Operlog/OperationLogEntity.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Operlog/OperationLogEntity.cs @@ -51,12 +51,12 @@ namespace Yi.Framework.Rbac.Domain.Operlog /// /// 请求参数 /// - [SugarColumn(ColumnName = "RequestParam")] + [SugarColumn(ColumnName = "RequestParam",ColumnDataType = StaticConfig.CodeFirst_BigString)] public string? RequestParam { get; set; } /// /// 请求结果 /// - [SugarColumn(ColumnName = "RequestResult", Length = 9999)] + [SugarColumn(ColumnName = "RequestResult",ColumnDataType = StaticConfig.CodeFirst_BigString)] public string? RequestResult { get; set; } public DateTime CreationTime { get; set; } diff --git a/Yi.Bbs.Vue3/src/assets/styles/login.css b/Yi.Bbs.Vue3/src/assets/styles/login.css index 6bdfa288..9a16c4dc 100644 --- a/Yi.Bbs.Vue3/src/assets/styles/login.css +++ b/Yi.Bbs.Vue3/src/assets/styles/login.css @@ -146,13 +146,7 @@ align-items: flex-end; height: 40px; text-align: center; } -.div-bottom -{ - position: absolute; - bottom: 30px; - color:#CAD2D9; - font-size: 12px; -} + .div-bottom span{ margin: 0 5px; cursor: pointer; diff --git a/Yi.Bbs.Vue3/src/hooks/useAuths.js b/Yi.Bbs.Vue3/src/hooks/useAuths.js index 8d4eab76..acee7595 100644 --- a/Yi.Bbs.Vue3/src/hooks/useAuths.js +++ b/Yi.Bbs.Vue3/src/hooks/useAuths.js @@ -108,7 +108,7 @@ const currentUserInfo=computed(()=>{ message: `您好${params.userName},登录成功!`, type: "success", }); - loginSuccess(res); + await loginSuccess(res); return res; } catch (error) { const { data } = error; diff --git a/Yi.Bbs.Vue3/src/layout/LoginLayout.vue b/Yi.Bbs.Vue3/src/layout/LoginLayout.vue index 14ff19e7..90bb6f1e 100644 --- a/Yi.Bbs.Vue3/src/layout/LoginLayout.vue +++ b/Yi.Bbs.Vue3/src/layout/LoginLayout.vue @@ -2,11 +2,24 @@ + + 备案: + 站长:{{ configStore.author }} + 联系我们 + 关于本站 + 建议反馈 + 原创站点 + + diff --git a/Yi.Bbs.Vue3/src/router/index.js b/Yi.Bbs.Vue3/src/router/index.js index 71e3020e..9fd58b5d 100644 --- a/Yi.Bbs.Vue3/src/router/index.js +++ b/Yi.Bbs.Vue3/src/router/index.js @@ -28,11 +28,11 @@ const router = createRouter({ // component: () => import("../views/Login.vue"), component: () => import("../views/login/index.vue"), }, - // { - // name: "register", - // path: "/register", - // component: () => import("../views/Register.vue"), - // }, + { + name: "register", + path: "/register", + component: () => import("../views/login/register.vue"), + }, { name: "auth", path: "/auth/:type", diff --git a/Yi.Bbs.Vue3/src/views/login/ForgotPassword.vue b/Yi.Bbs.Vue3/src/views/login/ForgotPassword.vue new file mode 100644 index 00000000..a4f76b28 --- /dev/null +++ b/Yi.Bbs.Vue3/src/views/login/ForgotPassword.vue @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/Yi.Bbs.Vue3/src/views/login/index.vue b/Yi.Bbs.Vue3/src/views/login/index.vue index 395383f4..49da43d7 100644 --- a/Yi.Bbs.Vue3/src/views/login/index.vue +++ b/Yi.Bbs.Vue3/src/views/login/index.vue @@ -1,7 +1,7 @@ - + Hello,you can go to homepage >> @@ -53,101 +53,18 @@ - + - - - - - - - - - - Thank Join to Yi! - - - - - - *登录账号 - - - - - - 昵称 - - - - - - - - *电话 - - - - {{codeInfo}} - - - - - *短信验证码 - - - - - - *密码 - - - - - - *确认密码 - - - - - - - - - 注册 - 前往登录 - - - - - - - 备案: - 站长:{{ configStore.author }} - 联系我们 - 关于本站 - 建议反馈 - 原创站点 - + + + + + + + + + + + Thank Join to Yi! + + + + + + *登录账号 + + + + + + + 昵称 + + + + + + + + *电话 + + + + {{codeInfo}} + + + + + *短信验证码 + + + + + + *密码 + + + + + + *确认密码 + + + + + + + + + 注册 + 前往登录 + + + + + + + + + \ No newline at end of file
Hello,you can go to homepage >>
Thank Join to Yi!
*登录账号
昵称
*电话
*短信验证码
*密码
*确认密码