ToB企服应用市场:ToB评测及商务社交产业平台

标题: .NET8 Identity Register [打印本页]

作者: 自由的羽毛    时间: 2024-5-22 16:10
标题: .NET8 Identity Register
分享给必要资助的人:记一次 IdentityAPI 中注册的源码解读,为什么有这篇文? 因为当我看到源码时,发现它的逻辑竟然是固定死的。我们并不是只能按照微软提供的源码去做。此文内容包含:设置用户账户为未验证状态延迟用户创建、优缺点的说明、适用场景。
在ASP.NET 8 Identity 中注册API的源码如下:
  1. routeGroup.MapPost("/register", async Task<Results<Ok, ValidationProblem>>
  2.     ([FromBody] RegisterRequest registration, HttpContext context, [FromServices] IServiceProvider sp) =>
  3. {
  4.     var userManager = sp.GetRequiredService<UserManager<TUser>>();
  5.     if (!userManager.SupportsUserEmail)
  6.     {
  7.         throw new NotSupportedException($"{nameof(MapIdentityApi)} requires a user store with email support.");
  8.     }
  9.     var userStore = sp.GetRequiredService<IUserStore<TUser>>();
  10.     var emailStore = (IUserEmailStore<TUser>)userStore;
  11.     var email = registration.Email;
  12.     if (string.IsNullOrEmpty(email) || !_emailAddressAttribute.IsValid(email))
  13.     {
  14.         return CreateValidationProblem(IdentityResult.Failed(userManager.ErrorDescriber.InvalidEmail(email)));
  15.     }
  16.     var user = new TUser { EmailConfirmed = false }; // 标记为未验证
  17.     await userStore.SetUserNameAsync(user, email, CancellationToken.None);
  18.     await emailStore.SetEmailAsync(user, email, CancellationToken.None);
  19.     var result = await userManager.CreateAsync(user, registration.Password);
  20.     if (!result.Succeeded)
  21.     {
  22.         return CreateValidationProblem(result);
  23.     }
  24.     await SendConfirmationEmailAsync(user, userManager, context, email);
  25.     return TypedResults.Ok();
  26. });
  27. routeGroup.MapGet("/confirm-email", async Task<IResult>
  28.     ([FromQuery] string userId, [FromQuery] string token, [FromServices] UserManager<TUser> userManager) =>
  29. {
  30.     var user = await userManager.FindByIdAsync(userId);
  31.     if (user == null)
  32.     {
  33.         return TypedResults.BadRequest("Invalid user.");
  34.     }
  35.     var result = await userManager.ConfirmEmailAsync(user, token);
  36.     if (!result.Succeeded)
  37.     {
  38.         return TypedResults.BadRequest("Email confirmation failed.");
  39.     }
  40.     user.EmailConfirmed = true; // 更新为已验证
  41.     await userManager.UpdateAsync(user);
  42.     return TypedResults.Ok("Email confirmed successfully.");
  43. });
复制代码
会发现它在注册的时候利用邮箱作为用户名,配置了邮箱和密码。但是它在发送邮箱验证码之前,就已经通过CreateAsync创建好了账号。这种方式叫做设置用户账户为未验证状态,将 EmailConfirmed 设置为 false,邮箱验证确认后设置为true。
这种方式的缺点很明显:
优点如下:
更安全的方式是延迟用户创建,代码如下:
  1. routeGroup.MapPost("/register", async Task<IResult>
  2.     ([FromBody] RegisterRequest registration, HttpContext context, [FromServices] IServiceProvider sp) =>
  3. {
  4.     var userManager = sp.GetRequiredService<UserManager<TUser>>();
  5.     if (!userManager.SupportsUserEmail)
  6.     {
  7.         throw new NotSupportedException($"{nameof(MapIdentityApi)} requires a user store with email support.");
  8.     }
  9.     var userStore = sp.GetRequiredService<IUserStore<TUser>>();
  10.     var emailStore = (IUserEmailStore<TUser>)userStore;
  11.     var email = registration.Email;
  12.     if (string.IsNullOrEmpty(email) || !_emailAddressAttribute.IsValid(email))
  13.     {
  14.         return CreateValidationProblem(IdentityResult.Failed(userManager.ErrorDescriber.InvalidEmail(email)));
  15.     }
  16.     // 生成验证令牌并发送确认邮件
  17.     var verificationToken = GenerateVerificationToken();
  18.     await SendVerificationEmailAsync(email, verificationToken, context);
  19.     // 临时保存注册信息
  20.     SaveTemporaryRegistrationInfo(registration, verificationToken);
  21.     return TypedResults.Ok("Please confirm your email.");
  22. });
  23. routeGroup.MapGet("/confirm-email", async Task<IResult>
  24.     ([FromQuery] string token, [FromServices] IServiceProvider sp) =>
  25. {
  26.     var registration = GetTemporaryRegistrationInfoByToken(token);
  27.     if (registration == null)
  28.     {
  29.         return TypedResults.BadRequest("Invalid or expired token.");
  30.     }
  31.     var userManager = sp.GetRequiredService<UserManager<TUser>>();
  32.     var user = new TUser();
  33.     await userStore.SetUserNameAsync(user, registration.Email, CancellationToken.None);
  34.     await emailStore.SetEmailAsync(user, registration.Email, CancellationToken.None);
  35.     var result = await userManager.CreateAsync(user, registration.Password);
  36.     if (!result.Succeeded)
  37.     {
  38.         return CreateValidationProblem(result);
  39.     }
  40.     return TypedResults.Ok("Email confirmed and user created.");
  41. });
复制代码
会发现它与第一个例子是相反的,它是用户注册后把数据保存在了临时的内存中,再向邮箱发送验证码。通过配置邮箱的时候,用验证码得到用户数据,并以此创建新的账号。
此做法的缺点也很明显:
优点如下:
它们的适用场景如下:

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4