ASP.NET Core 6.0 - SingleUser NuGet Package
This article describes the implementation of the KenHaggerty. Com. SingleUser. Net6 NuGet package. The package provides cookie authentication for a single user to an ASP.NET Core 6.0 Web Application. I will assume you have created a new ASP.NET Core 6.0 Razor Pages project. See Tutorial: Get started with Razor Pages in ASP.NET Core.
The .Net 5.0 RCL project, KenHaggerty. Com. SingleUser Razor Class Library is the result of a web app I developed. It was a simple web app which had Log In, Log Out, and Admin pages. I used a hard-coded user and cookie authentication to restrict access to Admin pages. Copying the pages into new projects was easier than copying the project and renaming the namespaces. I realized implementing authentication for a single user was the perfect candidate for my first NuGet package. The .Net 6.0 RCL project, KenHaggerty. Com. SingleUser. Net6 Razor Class Library has been upgraded to ASP.NET Core 6.0 with Visual Studio 2022 from the ASP.NET Core 5.0 project. I implemented a SingleUserLoginPartialModel with a NavLinkClass property. The RCL project is a copy of the source code used to publish the NuGet package at KenHaggerty. Com. SingleUser. Net6.
The research project has been upgraded to ASP.NET Core 6.0 with Visual Studio 2022 from the ASP.NET Core 5.0 project. I migrated the Startup.cs to top-level statements in Program.cs. I also implemented global usings and file scoped namespaces. I have enabled the nullable context and mitigated all warnings and issues. I have updated the project with Twitter Bootstrap v5. See ASP.NET Core 5.0 - Migrate To Bootstrap v5. This project implements Bootstrap Native. Details, screenshots, and related articles can be found at ASP.NET Core 6.0 - Hosted SingleUser Class Lib Project. The details page includes the version change log. Registered users on KenHaggerty. Com can download the source code for free at Manage > Assets.
KenHaggerty. Com. SingleUser. Net6 NuGet Package
Features
- A ServiceExtension which adds cookie authentication.
- Middleware which adds authentication to the ApplicationBuilder.
- Supports Bootstrap V5 and V4.
- Log In and Log Out pages reference the host's Shared/_Layout.cshtml.
- A default Admin/Index page.
- An optional password.
- An optional SingleUserPageTitleClass.
- A _SingleUserLoginPartial.cshtml and SingleUserLoginPartialModel.
- A SingleUserLoginPartialModel NavLinkClass property.
Quick Start
- Install KenHaggerty. Com. SingleUser. Net6.
- Edit the host web app's Program.cs or Startup.cs.
- Authorize the Admin folder.
- Add the _SingleUserLoginPartial to the host's Shared/_Layout.cshtml's navbar.
- Set options in appsettings.json.
- Build, run, and test.
Install KenHaggerty. Com. SingleUser. Net6.
- Manage NuGet Packages on the host.
- Search for kenhaggerty on the Browse tab.
- Select the Net6 version and install.
Edit the host web app's Program.cs or Startup.cs.
- Authorize the Admin folder.
- Add services.AddSingleUser();
- Add app.UseSingleUser();
Program.cs Template
// Configure Services with the WebApplicationBuilder. var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(options => { options.Conventions.AuthorizeFolder("/Admin"); }); builder.Services.AddSingleUser(); // Configure the HTTP request pipeline. var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseSingleUser(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
Startup.cs Template
public void ConfigureServices(IServiceCollection services) { services.AddRazorPage(options => { options.Conventions.AuthorizeFolder("/Admin"); }); services.AddSingleUser(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseSingleUser(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); }
Edit the host Shared/_Layout. cshtml
@using KenHaggerty. Com. SingleUser. Net6. Models;
- Add the _SingleUserLoginPartial with the SingleUserLoginPartialModel into the host's navbar.
- SingleUserLoginPartialModel NavLinkClass defaults to "text-dark".
- Override the SingleUserLoginPartialModel NavLinkClass on initialization.
navbar-collapse with flex-sm-row-reverse
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse"> <partial name="_SingleUserLoginPartial" model='@@new SingleUserLoginPartialModel() { NavLinkClass = "text-primary fw-bold"}' /> <ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Admin/Index">Admin</a> </li> </ul> </div>
navbar-collapse with justify-content-between
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between"> <ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Admin/Index">Admin</a> </li> </ul> <partial name="_SingleUserLoginPartial" model='@@new SingleUserLoginPartialModel() { NavLinkClass = "text-primary fw-bold"}' /> </div>
Password and SingleUserPageTitleClass (Optional)
For basic password support, add a SingleUserPassword key with your password to the host's appsettings. json's root. Use the SingleUserPageTitleClass option to match the host's css.
"SingleUserPassword": "Password", "SingleUserPageTitleClass": "text-primary"
KenHaggerty. Com. SingleUser. Net6 Implements
Log In and Log Out Pages
- Located in an Account folder/path.
- Reference the host's Shared/_Layout.cshtml.
- References the SingleUserPageTitleClass option in the host's appsettings.json.
Default Admin/Index Page
- Located in an Admin folder/path.
- References the host's Shared/_Layout.cshtml.
- Configuration hints and verification.
- Overridden by the host's Admin/Index page.
AddSingleUser Implements:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/account/login"; options.LogoutPath = "/account/logout"; options.AccessDeniedPath = "/account/accessdenied"; options.Cookie.SameSite = SameSiteMode.Strict; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; options.Cookie.IsEssential = true; });
UseSingleUser Implements:
app.UseAuthentication();
Page titles implement the optional SingleUserPageTitleClass:
@@page @@using Microsoft.Extensions.Configuration @@inject Microsoft.Extensions.Configuration.IConfiguration _config @@model LogInModel @@{ ViewData["Title"] = "Log In"; var singleUserPageTitleClass = _config.GetValue<string>("SingleUserPageTitleClass"); } <div class="text-center border-bottom mb-1"> <h1 class="@@(singleUserPageTitleClass ?? singleUserPageTitleClass)">@@ViewData["Title"]</<h1> </<div>
The Login page Implements a Bootstrap checkbox with both V4 and V5 checkbox classes.
Login.cshtml:
<div class="custom-control custom-checkbox form-check"> <input type="checkbox" class="custom-control-input form-check-input" asp-for="IsPersistent" /> <label class="custom-control-label form-check-label" asp-for="IsPersistent"> @@Html.DisplayNameFor(model => model.IsPersistent) </label> </div>
SingleUserLoginPartialModel Implements:
namespace KenHaggerty.Com.SingleUser.Net6.Models; public class SingleUserLoginPartialModel { public string NavLinkClass { get; set; } = "text-dark"; }
_SingleUserLoginPartial.cshtml Implements:
@@model SingleUserLoginPartialModel <ul class="navbar-nav"> @@if (User.Identity!.IsAuthenticated) { <li class="nav-item"> <form class="d-inline" asp-page="/Account/LogOut" method="post"> <button type="submit" class="nav-link @@(Model!.NavLinkClass) btn btn-link pt-1"> Log Out @@User.Identity.Name </button> </<form> </<li> } else { <li class="nav-item"> <a class="nav-link @@(Model!.NavLinkClass)" asp-page="/Account/LogIn">Log In</<a> </<li> } </<ul>
Comments(0)