Moderne applikationer bevæger sig i stigende grad væk fra traditionelle adgangskoder og over mod adgangskodefri autentificeringsmetoder, der både kan styrke sikkerheden og gøre login lettere for brugerne. I denne artikel viser jeg, hvordan brugere autentificeres i en ASP.NET Core applikation med FoxIDs og OpenID Connect, så de kan logge ind helt uden adgangskode med engangskoder sendt via e-mail.
Vi begynder med et tomt FoxIDs miljø, opretter en ny ASP.NET Core webapplikation, forbinder den med OpenID Connect og aktiverer til sidst adgangskodefrit login med e-mailbaseret OTP.
Opret et FoxIDs udviklingsmiljø
Jeg begyndte med at oprette et nyt, tomt udviklingsmiljø i FoxIDs. Et tomt miljø gør det overskueligt at konfigurere autentifikation fra bunden og gentage trinnene i jeres egen tenant.
Hvis I ikke har brugt FoxIDs før, kan I oprette en gratis tenant her:
Hver tenant indeholder to miljøer, der er klar til brug, så I frit kan afprøve opsætningen.
Konfigurér autentifikation
Begynd med at konfigurere, hvordan brugerne skal logge ind. Her skal brugerne logge ind uden adgangskode og kun bruge deres e-mailadresse og et engangskodeord (OTP), som sendes til dem.
- Vælg fanen Authentications i FoxIDs miljøet.
- Vælg Default — User Login UI.
- Deaktivér Password authentication under Authentication, og aktivér Passwordless with email (one-time password).
- Vælg Update for at gemme ændringerne.
Brugerne kan nu oprette en ny konto og logge ind uden adgangskode ved blot at indtaste deres e-mailadresse og den OTP, de modtager.
Opret ASP.NET Core applikationen
Nu skal vi bruge en applikation, som skal autentificere brugere. I kan bruge Visual Studio, VS Code eller et andet værktøj, der understøtter almindelig ASP.NET Core udvikling.
Læs artiklen “Adgangskodefri autentifikation i en AI-genereret ASP.NET Core app med FoxIDs og e-mail OTP”, hvis I vil generere ASP.NET Core applikationen med en AI-prompt.
I denne vejledning opretter jeg en enkel ASP.NET Core Razor Pages applikation til .NET 10 i Visual Studio. Den samme fremgangsmåde kan bruges med MVC, en Blazor Web App eller et andet ASP.NET Core projekt.
Kør applikationen. Eksempelapplikationen kører lokalt på https://localhost:7283/.
Eksempelkoden findes på GitHub.
Konfigurér webapplikationen i FoxIDs
Nu kender vi webapplikationens lokale adresse og kan registrere den i FoxIDs, så den kan autentificere brugere gennem OpenID Connect.
- Vælg fanen Applications i FoxIDs miljøet.
- Vælg New application og derefter Web application — OpenID Connect.
- Angiv et navn under Name, eksempelvis ASP.NET web application.
- Tilføj applikationens basisadresse under Redirect URI: https://localhost:7283/ FoxIDs tillader som standard omdirigering til efterfølgende sider under denne basisadresse. I kan kræve absolutte redirect URI'er, hvis valideringen skal være mere restriktiv.
- Vælg Create.
FoxIDs viser nu forbindelsesoplysningerne til den nye applikation, herunder:
- Authority
- Client ID
- Client Secret
Kopiér Authority og Client ID til projektets IdentitySettings sektion. Gem Client Secret lokalt i .NET user-secrets eller i en sikker miljøvariabel eller secret store i produktion.
Konfigurér autentifikation i ASP.NET applikationen
Når FoxIDs applikationen er oprettet, skal autentifikation konfigureres i ASP.NET Core projektet. Vi bruger cookie authentication til den lokale session og OpenID Connect til kommunikationen med FoxIDs.
Åbn Program.cs, og tilføj autentifikationskonfigurationen med builder.Services.AddAuthentication... og app.UseAuthentication();:
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Logging;
var builder = WebApplication.CreateBuilder(args);
// Detailed authentication errors can help locally, but must not be enabled in production.
if (builder.Environment.IsDevelopment())
{
IdentityModelEventSource.ShowPII = true;
}
// Add authentication with cookie and OpenID Connect
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Authority = builder.Configuration["IdentitySettings:Authority"];
options.ClientId = builder.Configuration["IdentitySettings:ClientId"];
options.ClientSecret = builder.Configuration["IdentitySettings:ClientSecret"];
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.Scope.Add("email");
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.MapInboundClaims = false;
options.TokenValidationParameters.NameClaimType = "sub";
options.TokenValidationParameters.RoleClaimType = "role";
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = async context =>
{
// Custom claims transformation or other logic can be added here.
await Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
if (!builder.Environment.IsDevelopment())
{
return Task.CompletedTask;
}
context.HandleResponse();
context.Response.StatusCode = 500;
context.Response.ContentType = "text/plain";
return context.Response.WriteAsync(context.Exception.ToString());
}
};
});
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllers();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapStaticAssets();
app.MapControllers();
app.MapRazorPages()
.WithStaticAssets();
app.Run();
Tilføj de ikke-fortrolige FoxIDs forbindelsesoplysninger i appsettings.json. Hold client secret ude af versionsstyringen, og indlæs den fra .NET user-secrets under lokal udvikling eller fra en sikker miljøvariabel eller secret store i produktion.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"IdentitySettings": {
"Authority": "https://foxids.com/{tenant}/{environment}/{application}/",
"ClientId": "your-client-id"
}
}
Gem client secret lokalt uden at skrive den i appsettings.json:
dotnet user-secrets init
dotnet user-secrets set "IdentitySettings:ClientSecret" "your-client-secret"
Erstat eksempelværdierne med Authority, Client ID og Client Secret fra jeres eget FoxIDs miljø. Den rigtige secret må aldrig committes.
Vis claims på forsiden
I dette eksempel vises claims på forsiden. Åbn Index.cshtml, og erstat indholdet:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
@if (User.Identity?.IsAuthenticated == true)
{
<h2 class="mt-4">Claims</h2>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Type</th>
<th>Value</th>
</tr>
</thead>
<tbody>
@foreach (var claim in User.Claims)
{
<tr>
<td>@claim.Type</td>
<td>@claim.Value</td>
</tr>
}
</tbody>
</table>
}
else
{
<p class="mt-4 text-muted">Not signed in.</p>
}
Tilføj en loginmenu i applikationen
For at brugerne kan logge ind, tilføjer vi en partial view med login- og logoutfunktioner.
Opret filen Pages/Shared/_LoginPartial.cshtml med følgende indhold:
@if (User.Identity?.IsAuthenticated == true)
{
<ul class="navbar-nav">
<li class="nav-item">
<form class="form-inline" asp-controller="Auth" asp-action="Logout" method="post">
@Html.AntiForgeryToken()
<button type="submit" class="nav-link btn btn-link text-dark">Log off</button>
</form>
</li>
</ul>
}
else
{
<ul class="navbar-nav navbar-right">
<li class="nav-item">
<a class="nav-link text-dark" asp-controller="Auth" asp-action="Login">Log in</a>
</li>
</ul>
}
Medtag derefter login partial i navigationsmenuen. Tilføj partial-elementet sidst i navigationslinjen i Pages/Shared/_Layout.cshtml:
<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="/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
</li>
</ul>
<partial name="_LoginPartial" />
</div>
Tilføj derefter endpoints til login- og logoutanmodninger. Opret mappen Controllers og controllerfilen Controllers/AuthController.cs med følgende indhold:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace WebAppPasswordLessEmail.Controllers
{
[AllowAnonymous]
[Route("[controller]/[action]")]
public class AuthController : Controller
{
[HttpGet]
public IActionResult Login()
{
var redirectUri = Url.Content("~/");
if (User.Identity?.IsAuthenticated == true)
{
return LocalRedirect(redirectUri);
}
return Challenge(new AuthenticationProperties { RedirectUri = redirectUri },
OpenIdConnectDefaults.AuthenticationScheme);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Logout()
{
var redirectUri = Url.Content("~/");
if (User.Identity?.IsAuthenticated != true)
{
return LocalRedirect(redirectUri);
}
return SignOut(new AuthenticationProperties { RedirectUri = redirectUri },
CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme);
}
}
}
Kør og genindlæs applikationen. Menupunktet Log in vises nu i topmenuen.
Log ind
Vælg Log in. I bliver omdirigeret til FoxIDs loginskærmen.
Vælg Create user.
Udfyld formularen Create user med jeres e-mailadresse eller en testadresse, I har adgang til, samt fornavn og efternavn. Vælg derefter Create.
Indtast det engangskodeord (OTP), I har modtaget via e-mail, og vælg Log in.
I er nu logget ind, og testbrugerens claims vises.
Prøv til sidst at logge ud og ind igen for at gennemføre det adgangskodefri loginflow med e-mail OTP.