我只是想知道如何处理以下情况。
我目前有一个asp.net mvc应用程序,我正在转换为asp.net核心。在旧的asp.net mvc应用程序中,我们从未收到过电子邮件确认。我打算强制所有现有用户和新用户在新的asp.net核心版本中确认电子邮件。我相信我可以通过Login控制器执行此操作。
问题 我面临的问题是,如果人们使用虚假的电子邮件地址或使用其他人的地址,那么他们就永远无法确认该电子邮件。
提出的解决方案 因此,我想到处理此问题的一种方法是,当用户登录时,我给他们一个选项来更改他们的电子邮件并将确认信息发送到这个新的电子邮件地址?
这是可取的吗?有什么好的替代方案可以解决这个问题?
我建议创建一个资源过滤器来检查用户的电子邮件是否已确认,如果没有重定向到视图来处理:
public class EmailConfirmedResourceFilter : IAsyncResourceFilter
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly IUrlHelperFactory _urlHelperFactory;
public EmailConfirmedResourceFilter(UserManager<ApplicationUser> userManager, IUrlHelperFactory urlHelperFactory)
{
_userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
_urlHelperFactory = urlHelperFactory ?? throw new ArgumentNullException(nameof(urlHelperFactory));
}
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
var urlHelper = _urlHelperFactory.GetUrlHelper(context);
var ignoreUrls = new[]
{
urlHelper.RouteUrl("ConfirmEmail"),
urlHelper.RouteUrl("ChangeEmail")
};
if (!ignoreUrls.Contains(context.HttpContext.Request.Path.ToString())
&& context.HttpContext.User.Identity.IsAuthenticated)
{
var user = await _userManager.GetUserAsync(context.HttpContext.User);
if (user != null && !await _userManager.IsEmailConfirmedAsync(user))
{
context.Result = new RedirectToRouteResult("ConfirmEmail");
}
}
await next();
}
}
然后,在Startup.cs
:
services.AddMvc(o => {
o.Filters.Add<EmailConfirmedResourceFilter>();
});
services.AddScoped<EmailConfirmedResourceFilter>();
这似乎是很多代码,但它非常简单。首先,过滤器调出一些应该被忽略的URL。如果我们在其中一个页面上,我们不希望再次重定向,特别是因为这可能会导致无限重定向循环。我们还检查用户是否经过身份验证,因为如果他们甚至没有登录,这都是一个没有实际意义的点。
假设这些测试通过,那么我们撤出用户并检查他们的电子邮件是否已确认。如果没有,我们会重定向到他们可以做到的地方。否则,一切都会落到await next();
行,它只是将控制传递给管道中的下一个东西(即我们什么都不做,让请求处理继续进行)。
这将导致用户在他们尝试在其他任何地方导航时强制用户访问电子邮件确认页面(如果他们尚未确认)。在所述页面上,您可以提供更改电子邮件地址的选项(这本身需要确认)或发送电子邮件以确认现有的电子邮件地址。一旦用户确认了任何一种方式,他们将绕过此检查,并能够继续前往他们想要在网站上的任何其他地方。