【发布时间】:2021-06-23 11:15:38
【问题描述】:
我已经在我的 Blazor 服务器端项目中实现了ASP.Net Core Identity,除了一个问题之外,我不时在 AspNetUsers 表中找到具有相同电子邮件地址的记录,即使我有下面在我的 Startup 课程中。
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.User.RequireUniqueEmail = true;
options.Lockout.AllowedForNewUsers = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
options.Lockout.MaxFailedAccessAttempts = 3;
})
.AddRoleManager<RoleManager<IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
我扩展了 ApplicationUser 以包含 DateRegistered 并且我注意到在重复的行中 DateRegistered 的差异很小,例如
2021-03-17 09:58:11.2442397
2021-03-17 09:58:11.2442398
在实现 Identity 时,我搭建了注册页面并进行了一项修改
注册.cshtml.cs
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
//check that the email address belongs to either a member, administrator or client
var isValidRegistrationEmail = await _applicationUserDataService.IsEmailAddressValidForRegistration(Input.Email);
if(isValidRegistrationEmail == false)
{
//we don't want to advise that the email address has not been found as this can be used by would be hackers
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
}
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email, DateRegistered = DateTime.Now };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
}
else
{
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
我所做的修改是插入以下代码,因为在此应用程序中只有选定的电子邮件地址应该能够注册。
//check that the email address belongs to either a member, administrator or client
var isValidRegistrationEmail = await _applicationUserDataService.IsEmailAddressValidForRegistration(Input.Email);
if(isValidRegistrationEmail == false)
{
//we don't want to advise that the email address has not been found as this can be used by would be hackers
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
}
在调查该问题时,我确实注意到生产服务器上的数据库缺少我现在添加的索引 UserNameIndex。
CREATE UNIQUE NONCLUSTERED INDEX [UserNameIndex] ON [dbo].[AspNetUsers]
(
[NormalizedUserName] ASC
)
WHERE ([NormalizedUserName] IS NOT NULL)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
在我看来,添加缺少的索引可以防止现在将重复条目添加到表 AspNetUsers 但是我想知道这是否会完全解决问题,或者用户现在是否会由于应用程序尝试而收到错误添加具有相同电子邮件地址的第二条记录。
很难测试,因为它不会每次都发生。
【问题讨论】:
-
肯定会向用户报告错误(如果您的服务器处理所有错误以向客户端返回消息)。所以需要解决添加新用户时为什么记录重复的问题。
-
我正在考虑添加缺少的索引是否会解决问题,或者这是否只是问题的一部分,我在修改注册页面时引入了一个问题
-
这是问题的一部分,您仍然需要那个缺失的索引。它是数据库层上的一种保护(验证器)。剩下的问题是应用层的错误行为,这将导致向客户端报告不必要的无意义错误。您的系统会很好,因为不会复制任何数据,但用户体验仍然不好,因为用户有时会看到奇怪的错误报告,尽管数据仍然可以提交/保存。
-
是的。这是我的恐惧,因为我不确定是什么导致了应用程序层的问题,因为我只是使用样板注册代码,除了我概述的一个附加项,我看不出这会如何导致问题.
标签: c# asp.net-core blazor-server-side