diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/IAccountAppService.cs b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/IAccountAppService.cs index 67c531ec02..1ff8cf2cdf 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/IAccountAppService.cs +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/IAccountAppService.cs @@ -10,5 +10,7 @@ public interface IAccountAppService : IApplicationService Task SendPasswordResetCodeAsync(SendPasswordResetCodeDto input); + Task VerifyPasswordResetTokenAsync(VerifyPasswordResetTokenInput input); + Task ResetPasswordAsync(ResetPasswordDto input); } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/VerifyPasswordResetTokenInput.cs b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/VerifyPasswordResetTokenInput.cs new file mode 100644 index 0000000000..1e90657018 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/VerifyPasswordResetTokenInput.cs @@ -0,0 +1,12 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Volo.Abp.Account; + +public class VerifyPasswordResetTokenInput +{ + public Guid UserId { get; set; } + + [Required] + public string ResetToken { get; set; } +} diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs index db45462f39..cc7cdd8c83 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs +++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs @@ -60,6 +60,16 @@ public class AccountAppService : ApplicationService, IAccountAppService await AccountEmailer.SendPasswordResetLinkAsync(user, resetToken, input.AppName, input.ReturnUrl, input.ReturnUrlHash); } + public virtual async Task VerifyPasswordResetTokenAsync(VerifyPasswordResetTokenInput input) + { + var user = await UserManager.GetByIdAsync(input.UserId); + return await UserManager.VerifyUserTokenAsync( + user, + UserManager.Options.Tokens.PasswordResetTokenProvider, + UserManager.ResetPasswordTokenPurpose, + input.ResetToken); + } + public virtual async Task ResetPasswordAsync(ResetPasswordDto input) { await IdentityOptions.SetAsync(); diff --git a/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.Generated.cs b/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.Generated.cs index e0535a0cd2..b92a60a604 100644 --- a/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.Generated.cs +++ b/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/AccountClientProxy.Generated.cs @@ -32,6 +32,14 @@ public partial class AccountClientProxy : ClientProxyBase, I }); } + public virtual async Task VerifyPasswordResetTokenAsync(VerifyPasswordResetTokenInput input) + { + return await RequestAsync(nameof(VerifyPasswordResetTokenAsync), new ClientProxyRequestTypeValue + { + { typeof(VerifyPasswordResetTokenInput), input } + }); + } + public virtual async Task ResetPasswordAsync(ResetPasswordDto input) { await RequestAsync(nameof(ResetPasswordAsync), new ClientProxyRequestTypeValue diff --git a/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/ProfileClientProxy.Generated.cs b/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/ProfileClientProxy.Generated.cs index 0f1bd18959..1c2ae7b3d8 100644 --- a/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/ProfileClientProxy.Generated.cs +++ b/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/ProfileClientProxy.Generated.cs @@ -6,7 +6,7 @@ using Volo.Abp.Http.Client; using Volo.Abp.Http.Modeling; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; -using Volo.Abp.Identity; +using Volo.Abp.Account; // ReSharper disable once CheckNamespace namespace Volo.Abp.Account.ClientProxies; diff --git a/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json b/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json index c6152dbd74..1fd443328a 100644 --- a/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json +++ b/modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json @@ -7,6 +7,8 @@ "Volo.Abp.Account.AccountController": { "controllerName": "Account", "controllerGroupName": "Account", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Abp.Account.AccountController", "interfaces": [ { @@ -88,6 +90,43 @@ "allowAnonymous": null, "implementFrom": "Volo.Abp.Account.IAccountAppService" }, + "VerifyPasswordResetTokenAsyncByInput": { + "uniqueName": "VerifyPasswordResetTokenAsyncByInput", + "name": "VerifyPasswordResetTokenAsync", + "httpMethod": "POST", + "url": "api/account/verify-password-reset-token", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Abp.Account.VerifyPasswordResetTokenInput, Volo.Abp.Account.Application.Contracts", + "type": "Volo.Abp.Account.VerifyPasswordResetTokenInput", + "typeSimple": "Volo.Abp.Account.VerifyPasswordResetTokenInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Abp.Account.VerifyPasswordResetTokenInput", + "typeSimple": "Volo.Abp.Account.VerifyPasswordResetTokenInput", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Boolean", + "typeSimple": "boolean" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.Account.IAccountAppService" + }, "ResetPasswordAsyncByInput": { "uniqueName": "ResetPasswordAsyncByInput", "name": "ResetPasswordAsync", @@ -130,6 +169,8 @@ "Volo.Abp.Account.Web.Areas.Account.Controllers.AccountController": { "controllerName": "Account", "controllerGroupName": "Login", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Abp.Account.Web.Areas.Account.Controllers.AccountController", "interfaces": [], "actions": { @@ -227,6 +268,8 @@ "Volo.Abp.Account.ProfileController": { "controllerName": "Profile", "controllerGroupName": "Profile", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Abp.Account.ProfileController", "interfaces": [ { @@ -329,4 +372,4 @@ } }, "types": {} -} +} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs b/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs index 39df700928..c262c6a4cb 100644 --- a/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/AccountController.cs @@ -31,6 +31,13 @@ public class AccountController : AbpControllerBase, IAccountAppService return AccountAppService.SendPasswordResetCodeAsync(input); } + [HttpPost] + [Route("verify-password-reset-token")] + public Task VerifyPasswordResetTokenAsync(VerifyPasswordResetTokenInput input) + { + return AccountAppService.VerifyPasswordResetTokenAsync(input); + } + [HttpPost] [Route("reset-password")] public virtual Task ResetPasswordAsync(ResetPasswordDto input) diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml index 40b8d87048..eb017599ea 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml @@ -1,20 +1,31 @@ @page @inject IHtmlLocalizer L +@inject IHtmlLocalizer LI @using Microsoft.AspNetCore.Mvc.Localization @using Volo.Abp.Account.Localization +@using Volo.Abp.Identity.Localization @model Volo.Abp.Account.Web.Pages.Account.ResetPasswordModel @inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout

@L["ResetPassword"]

-
-

@L["ResetPassword_Information"]

- - - - - @L["Cancel"] - - + @if (Model.InvalidToken) + { +
+ @LI["Volo.Abp.Identity:InvalidToken"] +
+ } + else + { +
+

@L["ResetPassword_Information"]

+ + + + + @L["Cancel"] + + + }
diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml.cs index 8725e1d8cd..c0d7ebb9cf 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/ResetPassword.cshtml.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Auditing; using Volo.Abp.Identity; @@ -43,9 +44,21 @@ public class ResetPasswordModel : AccountPageModel [DisableAuditing] public string ConfirmPassword { get; set; } - public virtual Task OnGetAsync() + public bool InvalidToken { get; set; } + + public virtual async Task OnGetAsync() { - return Task.FromResult(Page()); + ValidateModel(); + + InvalidToken = !await AccountAppService.VerifyPasswordResetTokenAsync( + new VerifyPasswordResetTokenInput + { + UserId = UserId, + ResetToken = ResetToken + } + ); + + return Page(); } public virtual async Task OnPostAsync() diff --git a/modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js b/modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js index 7a6ed6f47f..2e291710d5 100644 --- a/modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js +++ b/modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js @@ -5,67 +5,75 @@ (function(){ - // controller volo.abp.account.web.areas.account.controllers.account + // controller volo.abp.account.account (function(){ - abp.utils.createNamespace(window, 'volo.abp.account.web.areas.account.controllers.account'); + abp.utils.createNamespace(window, 'volo.abp.account.account'); - volo.abp.account.web.areas.account.controllers.account.login = function(login, ajaxParams) { + volo.abp.account.account.register = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/account/login', + url: abp.appPath + 'api/account/register', type: 'POST', - data: JSON.stringify(login) + data: JSON.stringify(input) }, ajaxParams)); }; - volo.abp.account.web.areas.account.controllers.account.logout = function(ajaxParams) { + volo.abp.account.account.sendPasswordResetCode = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/account/logout', - type: 'GET', - dataType: null + url: abp.appPath + 'api/account/send-password-reset-code', + type: 'POST', + dataType: null, + data: JSON.stringify(input) }, ajaxParams)); }; - volo.abp.account.web.areas.account.controllers.account.checkPassword = function(login, ajaxParams) { + volo.abp.account.account.verifyPasswordResetToken = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/account/check-password', + url: abp.appPath + 'api/account/verify-password-reset-token', type: 'POST', - data: JSON.stringify(login) + data: JSON.stringify(input) + }, ajaxParams)); + }; + + volo.abp.account.account.resetPassword = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/account/reset-password', + type: 'POST', + dataType: null, + data: JSON.stringify(input) }, ajaxParams)); }; })(); - // controller volo.abp.account.account + // controller volo.abp.account.web.areas.account.controllers.account (function(){ - abp.utils.createNamespace(window, 'volo.abp.account.account'); + abp.utils.createNamespace(window, 'volo.abp.account.web.areas.account.controllers.account'); - volo.abp.account.account.register = function(input, ajaxParams) { + volo.abp.account.web.areas.account.controllers.account.login = function(login, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/account/register', + url: abp.appPath + 'api/account/login', type: 'POST', - data: JSON.stringify(input) + data: JSON.stringify(login) }, ajaxParams)); }; - volo.abp.account.account.sendPasswordResetCode = function(input, ajaxParams) { + volo.abp.account.web.areas.account.controllers.account.logout = function(ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/account/send-password-reset-code', - type: 'POST', - dataType: null, - data: JSON.stringify(input) + url: abp.appPath + 'api/account/logout', + type: 'GET', + dataType: null }, ajaxParams)); }; - volo.abp.account.account.resetPassword = function(input, ajaxParams) { + volo.abp.account.web.areas.account.controllers.account.checkPassword = function(login, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/account/reset-password', + url: abp.appPath + 'api/account/check-password', type: 'POST', - dataType: null, - data: JSON.stringify(input) + data: JSON.stringify(login) }, ajaxParams)); };