 b24beb3154
			
		
	
	
		b24beb3154
		
	
	
	
	
		
			
			This commit integrates ASP.NET Core Identity into the application to enable user registration, login, and management. This lays the groundwork for securing data per user.
**Key Changes:**
*   **DbContext Configuration:**
    *   Modified `ApplicationDbContext.cs` to inherit from `IdentityDbContext<IdentityUser>`.
    *   Removed an unnecessary `using` statement from `ApplicationDbContext.cs`.
*   **Program.cs Setup:**
    *   Configured `AddDefaultIdentity<IdentityUser>` with `AddEntityFrameworkStores<ApplicationDbContext>()` to register Identity services.
    *   Ensured correct ordering of `UseAuthentication()` and `UseAuthorization()` middleware.
    *   Added `app.MapRazorPages()` to enable the Identity UI pages.
    *   Verified core package versions in `turf_tasker.csproj` for consistency across EF Core and Identity components (`8.0.6`).
*   **Identity UI:**
    *   Scaffolded ASP.NET Core Identity pages (Login, Register, Manage, etc.) to provide the user interface for authentication.
    *   Added a `_LoginPartial.cshtml` partial view to the `Views/Shared` folder.
    *   Rendered `_LoginPartial` in `Views/Shared/_Layout.cshtml` to display login/register/logout links in the navigation bar.
*   **Migrations:**
    *   Created and applied a new migration (`AddIdentitySchema`) to create the necessary ASP.NET Core Identity database tables (e.g., `AspNetUsers`, `AspNetRoles`).
		
	
			
		
			
				
	
	
		
			180 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| // Licensed to the .NET Foundation under one or more agreements.
 | |
| // The .NET Foundation licenses this file to you under the MIT license.
 | |
| #nullable disable
 | |
| 
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.ComponentModel.DataAnnotations;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using System.Text.Encodings.Web;
 | |
| using System.Threading;
 | |
| using System.Threading.Tasks;
 | |
| using Microsoft.AspNetCore.Authentication;
 | |
| using Microsoft.AspNetCore.Authorization;
 | |
| using Microsoft.AspNetCore.Identity;
 | |
| using Microsoft.AspNetCore.Identity.UI.Services;
 | |
| using Microsoft.AspNetCore.Mvc;
 | |
| using Microsoft.AspNetCore.Mvc.RazorPages;
 | |
| using Microsoft.AspNetCore.WebUtilities;
 | |
| using Microsoft.Extensions.Logging;
 | |
| 
 | |
| namespace turf_tasker.Areas.Identity.Pages.Account
 | |
| {
 | |
|     public class RegisterModel : PageModel
 | |
|     {
 | |
|         private readonly SignInManager<IdentityUser> _signInManager;
 | |
|         private readonly UserManager<IdentityUser> _userManager;
 | |
|         private readonly IUserStore<IdentityUser> _userStore;
 | |
|         private readonly IUserEmailStore<IdentityUser> _emailStore;
 | |
|         private readonly ILogger<RegisterModel> _logger;
 | |
|         private readonly IEmailSender _emailSender;
 | |
| 
 | |
|         public RegisterModel(
 | |
|             UserManager<IdentityUser> userManager,
 | |
|             IUserStore<IdentityUser> userStore,
 | |
|             SignInManager<IdentityUser> signInManager,
 | |
|             ILogger<RegisterModel> logger,
 | |
|             IEmailSender emailSender)
 | |
|         {
 | |
|             _userManager = userManager;
 | |
|             _userStore = userStore;
 | |
|             _emailStore = GetEmailStore();
 | |
|             _signInManager = signInManager;
 | |
|             _logger = logger;
 | |
|             _emailSender = emailSender;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
 | |
|         ///     directly from your code. This API may change or be removed in future releases.
 | |
|         /// </summary>
 | |
|         [BindProperty]
 | |
|         public InputModel Input { get; set; }
 | |
| 
 | |
|         /// <summary>
 | |
|         ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
 | |
|         ///     directly from your code. This API may change or be removed in future releases.
 | |
|         /// </summary>
 | |
|         public string ReturnUrl { get; set; }
 | |
| 
 | |
|         /// <summary>
 | |
|         ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
 | |
|         ///     directly from your code. This API may change or be removed in future releases.
 | |
|         /// </summary>
 | |
|         public IList<AuthenticationScheme> ExternalLogins { get; set; }
 | |
| 
 | |
|         /// <summary>
 | |
|         ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
 | |
|         ///     directly from your code. This API may change or be removed in future releases.
 | |
|         /// </summary>
 | |
|         public class InputModel
 | |
|         {
 | |
|             /// <summary>
 | |
|             ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
 | |
|             ///     directly from your code. This API may change or be removed in future releases.
 | |
|             /// </summary>
 | |
|             [Required]
 | |
|             [EmailAddress]
 | |
|             [Display(Name = "Email")]
 | |
|             public string Email { get; set; }
 | |
| 
 | |
|             /// <summary>
 | |
|             ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
 | |
|             ///     directly from your code. This API may change or be removed in future releases.
 | |
|             /// </summary>
 | |
|             [Required]
 | |
|             [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
 | |
|             [DataType(DataType.Password)]
 | |
|             [Display(Name = "Password")]
 | |
|             public string Password { get; set; }
 | |
| 
 | |
|             /// <summary>
 | |
|             ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
 | |
|             ///     directly from your code. This API may change or be removed in future releases.
 | |
|             /// </summary>
 | |
|             [DataType(DataType.Password)]
 | |
|             [Display(Name = "Confirm password")]
 | |
|             [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
 | |
|             public string ConfirmPassword { get; set; }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public async Task OnGetAsync(string returnUrl = null)
 | |
|         {
 | |
|             ReturnUrl = returnUrl;
 | |
|             ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
 | |
|         }
 | |
| 
 | |
|         public async Task<IActionResult> OnPostAsync(string returnUrl = null)
 | |
|         {
 | |
|             returnUrl ??= Url.Content("~/");
 | |
|             ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
 | |
|             if (ModelState.IsValid)
 | |
|             {
 | |
|                 var user = CreateUser();
 | |
| 
 | |
|                 await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
 | |
|                 await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
 | |
|                 var result = await _userManager.CreateAsync(user, Input.Password);
 | |
| 
 | |
|                 if (result.Succeeded)
 | |
|                 {
 | |
|                     _logger.LogInformation("User created a new account with password.");
 | |
| 
 | |
|                     var userId = await _userManager.GetUserIdAsync(user);
 | |
|                     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 = userId, 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();
 | |
|         }
 | |
| 
 | |
|         private IdentityUser CreateUser()
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 return Activator.CreateInstance<IdentityUser>();
 | |
|             }
 | |
|             catch
 | |
|             {
 | |
|                 throw new InvalidOperationException($"Can't create an instance of '{nameof(IdentityUser)}'. " +
 | |
|                     $"Ensure that '{nameof(IdentityUser)}' is not an abstract class and has a parameterless constructor, or alternatively " +
 | |
|                     $"override the register page in /Areas/Identity/Pages/Account/Register.cshtml");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private IUserEmailStore<IdentityUser> GetEmailStore()
 | |
|         {
 | |
|             if (!_userManager.SupportsUserEmail)
 | |
|             {
 | |
|                 throw new NotSupportedException("The default UI requires a user store with email support.");
 | |
|             }
 | |
|             return (IUserEmailStore<IdentityUser>)_userStore;
 | |
|         }
 | |
|     }
 | |
| }
 |