Moderne toepassingen wijken steeds meer af van traditionele wachtwoorden en gaan over op wachtwoordloze authenticatiemethoden die zowel veiliger als gemakkelijker zijn voor gebruikers. In dit bericht laat ik zien hoe je gebruikers kunt authenticeren in een ASP.NET Core-applicatie met behulp van FoxIDs met OpenID Connect) en een volledig wachtwoordloze aanmeldingservaring mogelijk kunt maken met behulp van eenmalige codes geleverd via e-mail.
We beginnen vanuit een schone FoxIDs omgeving, maken een nieuwe ASP.NET Core-webapp, verbinden deze met OpenID Connect en schakelen ten slotte passwordless-aanmelding in met op e-mail gebaseerde OTP.
Een FoxIDs ontwikkelomgeving maken
Ik begon met het maken van een nieuwe lege ontwikkelomgeving in FoxIDs. Een schone omgeving maakt het eenvoudig om authenticatie helemaal opnieuw in te stellen en zorgt ervoor dat u deze stappen in uw eigen tenant kunt repliceren.
Als u FoxIDs nog niet eerder hebt gebruikt, kunt u een gratis tenant maken op:
Elke tenant wordt geleverd met twee kant-en-klare omgevingen, zodat u vrij kunt experimenteren.
Configureer verificatie
Begin met het configureren van hoe gebruikers moeten inloggen. In dit geval willen we dat gebruikers zich zonder wachtwoord aanmelden, met alleen hun e-mailadres en een eenmalig wachtwoord (OTP) dat naar hen is verzonden.
- Selecteer het tabblad Authenticaties in uw FoxIDs omgeving.
- Klik op Standaard: gebruikersaanmeldingsinterface.
- In de sectie Authenticatie schakelt u Wachtwoordverificatie uit en schakelt u Wachtwoordloos met e-mail (eenmalig wachtwoord) in.
- Klik op Bijwerken om de wijzigingen op te slaan.
Hierdoor kunnen gebruikers een nieuw account aanmaken en wordt een wachtwoordloze ervaring geboden waarbij ze zich eenvoudigweg verifiëren door hun e-mailadres en de OTP die ze ontvangen in te voeren.
De ASP.NET Core-applicatie maken
Vervolgens hebben we een applicatie nodig om te authenticeren. U kunt Visual Studio of VS Code gebruiken: alles dat de standaard ASP.NET Core-ontwikkeling ondersteunt.
Lees het bericht "Wachtwoordloze authenticatie in een AI-gegenereerde ASP.NET Core-app met FoxIDs en op e-mail gebaseerde OTP" als u de ASP.NET Core-applicatie wilt genereren met een AI-prompt.
Voor deze walkthrough maak ik een eenvoudige ASP.NET Core Razor Pages-applicatie gericht op .NET 10 in Visual Studio, maar dezelfde aanpak werkt voor MVC, een Blazor Web App of elk ander ASP.NET Core-project.
Voer de app uit; de voorbeeld-app draait lokaal op https://localhost:7283/
U kunt de voorbeeldcode vinden in: https://github.com/ITfoxtec/dotnet.samples/tree/main/WebAppPasswordLessEmail
Configureer de webapplicatie in FoxIDs
Nu we het lokale adres van de webapplicatie kennen, kunnen we deze registreren in FoxIDs, zodat gebruikers kunnen worden geverifieerd via OpenID Connect.
- Selecteer het tabblad Applicaties in uw FoxIDs omgeving.
- Kies Nieuwe applicatie en selecteer vervolgens Webapplicatie — OpenID Connect.
- Voer bij Naam een naam in, bijvoorbeeld: ASP.NET webapplicatie.
- Voeg in de Redirect URI het basisadres van de applicatie toe: https://localhost:7283/ FoxIDs staat standaard toe dat u doorverwijst naar een volgende pagina onder deze basis-URL. Als u de voorkeur geeft aan striktere validatie, kunt u absolute omleidings-URI's vereisen.
- Klik op Maken.
FoxIDs geeft nu de verbindingsgegevens voor uw nieuwe applicatie weer, waaronder:
- Authority
- Klant-ID
- Cliëntgeheim
Kopieer de Authority en Client-ID naar de IdentitySettings-sectie van het project. Sla het Clientgeheim lokaal op in .NET gebruikersgeheimen of in een beveiligde omgevingsvariabele of geheime opslag in productie.
Configureer authenticatie in de ASP.NET applicatie
Nu de FoxIDs applicatie is gemaakt, is de volgende stap het configureren van authenticatie in het ASP.NET Core-project. We gebruiken cookie-authenticatie voor de lokale sessie en OpenID Connect om te communiceren met FoxIDs.
Open Program.cs en voeg de authenticatieconfiguratie toe met (builder.Services.AddAuthentication... en 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();
Voeg de niet-geheime FoxIDs verbindingsgegevens toe aan appsettings.json. Houd het clientgeheim buiten het bronbeheer en laad het vanuit .NET gebruikersgeheimen tijdens lokale ontwikkeling of vanuit een veilige omgevingsvariabele of geheime opslag in productie.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"IdentitySettings": {
"Authority": "https://foxids.com/{tenant}/{environment}/{application}/",
"ClientId": "your-client-id"
}
}
Sla het clientgeheim lokaal op zonder het naar appsettings.json te schrijven:
dotnet user-secrets init
dotnet user-secrets set "IdentitySettings:ClientSecret" "your-client-secret"
Vervang de voorbeeldwaarden door Authority, Client ID en Client Secret uit uw eigen FoxIDs omgeving. Bega nooit het echte geheim.
Toon claims op de hoofdpagina
Voor de doeleinden van dit voorbeeld worden claims op de hoofdpagina weergegeven. Open Index.cshtml en wijzig de inhoud:
@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>
}
Voeg een inlogmenu toe aan de applicatie
Om gebruikers te laten inloggen, voegen we een gedeeltelijke weergave toe voor in- en uitlogopties.
Maak een nieuw bestand: Pages/Shared/_LoginPartial.cshtml met de inhoud:
@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>
}
Neem dan de login gedeeltelijk op in het navigatiemenu. Voeg in Pages/Shared/_Layout.cshtml het gedeeltelijke login-element toe aan het einde van de navigatiebalk:
<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>
Voeg vervolgens een landingspagina toe voor de in- en uitlogverzoeken. Maak een map Controllers en maak een nieuw controllerbestand in de map: Controllers/AuthController.cs met de inhoud:
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);
}
}
}
Start de applicatie en laad deze opnieuw. U ziet nu een optie Inloggen in het hoofdmenu.
Inloggen
Klik op Inloggen en u wordt doorgestuurd naar het inlogscherm van FoxIDs.
Selecteer Gebruiker aanmaken.
Vul het formulier Gebruiker aanmaken in met uw e-mailadres (of een test-e-mailadres waartoe u toegang heeft), voornaam en achternaam en klik vervolgens op Aanmaken.
Voer het eenmalige wachtwoord (OTP) in dat u per e-mail heeft ontvangen en klik vervolgens op Inloggen.
U bent ingelogd en de claims van uw testgebruiker worden weergegeven.
Probeer vervolgens uit te loggen en opnieuw in te loggen om de wachtwoordloze inlogstroom te ervaren met behulp van e-mail OTP.