ASP.NET Core托管Blazor应用自定义密码邮箱重置实现咨询
实现方案
问题原因
你之前访问默认重置页面报错的原因是:脚手架生成的ResetPasswordModel是为「用户点击邮件重置链接」的场景设计的,必须携带Identity生成的加密重置token(也就是提示里的code)才能正常加载,不适合无邮件流程的自定义需求,不需要硬改原有文件,新增自定义Razor页面实现更简单。
前置安全要求
- 必须给重置页面加权限控制:如果是管理员给其他用户重置,加
[Authorize(Roles = "Admin")]特性;如果是登录用户改自己的账号,加[Authorize]特性,绝对不能开放匿名访问。
实现步骤
1. 新增自定义Razor页面
在Areas/Identity/Pages/Account目录下新增两个文件:CustomReset.cshtml和CustomReset.cshtml.cs
2. 编写PageModel后端逻辑
CustomReset.cshtml.cs示例代码:
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System.ComponentModel.DataAnnotations; // 替换为你自己的项目命名空间 namespace YourAppNamespace.Areas.Identity.Pages.Account { // 按需修改权限特性,管理员使用就加Roles参数 [Authorize(Roles = "Admin")] public class CustomResetModel : PageModel { private readonly UserManager<IdentityUser> _userManager; public CustomResetModel(UserManager<IdentityUser> userManager) { _userManager = userManager; } [BindProperty] public InputModel Input { get; set; } public class InputModel { [Required] [EmailAddress] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "密码长度至少6位", MinimumLength = 6)] [DataType(DataType.Password)] public string NewPassword { get; set; } [DataType(DataType.Password)] [Compare("NewPassword", ErrorMessage = "两次输入的密码不一致")] public string ConfirmPassword { get; set; } // 不需要修改邮箱可以删掉这个字段 [EmailAddress] public string? NewEmail { get; set; } } public void OnGet() { } public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } // 根据输入的邮箱查找目标用户 var user = await _userManager.FindByEmailAsync(Input.Email); if (user == null) { ModelState.AddModelError(string.Empty, "用户不存在"); return Page(); } // 1. 重置密码逻辑:内部生成重置token,无需发送邮件 var resetToken = await _userManager.GeneratePasswordResetTokenAsync(user); var resetPwdResult = await _userManager.ResetPasswordAsync(user, resetToken, Input.NewPassword); if (!resetPwdResult.Succeeded) { foreach (var error in resetPwdResult.Errors) { ModelState.AddModelError(string.Empty, error.Description); } return Page(); } // 2. 修改邮箱逻辑(不需要修改邮箱可以删除这部分) if (!string.IsNullOrEmpty(Input.NewEmail) && Input.NewEmail != Input.Email) { var changeEmailToken = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); var changeEmailResult = await _userManager.ChangeEmailAsync(user, Input.NewEmail, changeEmailToken); if (!changeEmailResult.Succeeded) { foreach (var error in changeEmailResult.Errors) { ModelState.AddModelError(string.Empty, error.Description); } return Page(); } // 如果你的业务逻辑中用户名和邮箱一致,同步更新用户名 await _userManager.SetUserNameAsync(user, Input.NewEmail); } // 重置成功后跳转,按需修改目标路径 return RedirectToPage("./ResetConfirmation"); } } }
3. 编写前端页面代码
CustomReset.cshtml示例代码:
@page "/customreset" @model CustomResetModel @{ ViewData["Title"] = "账号重置"; } <h1>@ViewData["Title"]</h1> <hr /> <div class="row"> <div class="col-md-4"> <form method="post"> <div asp-validation-summary="All" class="text-danger"></div> <div class="form-group"> <label asp-for="Input.Email">目标用户原邮箱</label> <input asp-for="Input.Email" class="form-control" /> <span asp-validation-for="Input.Email" class="text-danger"></span> </div> <!-- 不需要修改邮箱就删掉这个字段 --> <div class="form-group"> <label asp-for="Input.NewEmail">新邮箱(不需要修改可不填)</label> <input asp-for="Input.NewEmail" class="form-control" /> <span asp-validation-for="Input.NewEmail" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Input.NewPassword">新密码</label> <input asp-for="Input.NewPassword" class="form-control" /> <span asp-validation-for="Input.NewPassword" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Input.ConfirmPassword">确认新密码</label> <input asp-for="Input.ConfirmPassword" class="form-control" /> <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary">提交重置</button> </form> </div> </div> @section Scripts { <partial name="_ValidationScriptsPartial" /> }
可选优化
- 如果是登录用户修改自己的账号,不需要输入原邮箱,直接通过
await _userManager.GetUserAsync(User)获取当前登录用户即可,安全性更高 - 用户改自己密码时可增加旧密码校验逻辑,调用
ChangePasswordAsync方法实现,不需要生成重置token
内容的提问来源于stack exchange,提问作者Krellex
相关产品推荐
相关产品推荐

