Multifaktorautentisering i ASP.NET Core
Not
Det här är inte den senaste versionen av den här artikeln. Den aktuella versionen finns i den .NET 9-versionen av den här artikeln.
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. För den aktuella utgåvan, se .NET 9-versionen av den här artikeln .
Viktig
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
För den aktuella utgåvan, se .NET 9-versionen av den här artikeln .
Visa eller ladda ned exempelkod (damienbod/AspNetCoreHybridFlowWithApi GitHub-lagringsplats)
Multifaktorautentisering (MFA) är en process där en användare begärs under en inloggningshändelse för ytterligare former av identifiering. Den här uppmaningen kan vara att ange en kod från en mobiltelefon, använda en FIDO2-nyckel eller att tillhandahålla en fingeravtrycksgenomsökning. När du behöver en andra form av autentisering förbättras säkerheten. Den ytterligare faktorn är inte lätt att få tag på eller dupliceras av en cyberattacker.
Den här artikeln beskriver följande områden:
- Vad är MFA och vilka MFA-flöden som rekommenderas
- Konfigurera MFA för administrationssidor med hjälp av ASP.NET Core Identity
- Skicka MFA-inloggningskrav till OpenID Connect-servern
- Tvinga ASP.NET Core OpenID Connect-klienten att kräva MFA
MFA, 2FA
MFA kräver minst två eller flera typer av bevis för en identitet som något du vet, något du har eller biometrisk validering för att användaren ska kunna autentisera.
Tvåfaktorautentisering (2FA) är som en delmängd av MFA, men skillnaden är att MFA kan kräva två eller flera faktorer för att bevisa identiteten.
2FA stöds som standard när du använder ASP.NET Core Identity. Om du vill aktivera eller inaktivera 2FA för en viss användare anger du egenskapen IdentityUser<TKey>.TwoFactorEnabled. Standardgränssnittet för ASP.NET Core Identity innehåller sidor för att konfigurera 2FA.
MFA TOTP (tidsbaserad engångslösenordalgoritm)
MFA med TOTP stöds som standard när du använder ASP.NET Core Identity. Den här metoden kan användas tillsammans med alla kompatibla autentiseringsappar, inklusive:
- Microsoft Authenticator
- Google Authenticator
Mer information om implementering finns i Aktivera QR Code-generering för TOTP-autentiseringsappar i ASP.NET Core.
Om du vill inaktivera stöd för MFA TOTP konfigurerar du autentisering med AddIdentity i stället för AddDefaultIdentity.
AddDefaultIdentity
anropar AddDefaultTokenProviders internt, vilket registrerar flera tokenprovidrar, inklusive en för MFA TOTP. Om du bara vill registrera specifika tokenprovidrar anropar du AddTokenProvider för varje obligatorisk provider. Mer information om tillgängliga tokenprovidrar finns i AddDefaultTokenProviders
referenskälla (dotnet/aspnetcore
GitHub-lagringsplats).
Obs
Dokumentationslänkar till .NET-referenskällan läser vanligtvis in lagringsplatsens standardgren, vilket representerar den aktuella utvecklingen för nästa version av .NET. Om du vill välja en tagg för en specifik version använder du listrutan Växla grenar eller taggar. Mer information finns i Så här väljer du en versionstagg för ASP.NET Core-källkod (dotnet/AspNetCore.Docs #26205).
MFA-nyckel/FIDO2 eller lösenordslös
passkeys/FIDO2 är för närvarande:
- Det säkraste sättet att uppnå MFA.
- MFA som skyddar mot phishingattacker. (Förutom certifikatautentisering och Windows för företag)
För närvarande stöder ASP.NET Core inte passkeys/FIDO2 direkt. Lösenord/FIDO2 kan användas för MFA- eller lösenordslösa flöden.
Microsoft Entra ID ger stöd för passkeys/FIDO2 och lösenordslösa flöden. Mer information finns i alternativ för lösenordsfri autentisering.
Andra typer av lösenordsfri MFA skyddar inte nödvändigtvis mot nätfiske.
MFA (flerfaktorsautentisering) SMS
MFA med SMS ökar säkerheten kraftigt jämfört med lösenordsautentisering (enskild faktor). Att använda SMS som en andra faktor rekommenderas dock inte längre. Det finns för många kända attackvektorer för den här typen av implementering.
Konfigurera MFA för administrationssidor med hjälp av ASP.NET Core Identity
MFA kan tvingas på användare för att de ska få tillgång till känsliga sidor i en ASP.NET Core Identity-app. Detta kan vara användbart för appar där det finns olika åtkomstnivåer för de olika identiteterna. Användare kanske till exempel kan visa profildata med hjälp av en lösenordsinloggning, men en administratör måste använda MFA för att få åtkomst till de administrativa sidorna.
Utöka inloggningen med ett MFA-anspråk
Demokoden konfigureras med hjälp av ASP.NET Core med Identity och Razor Pages. Metoden AddIdentity
används i stället för AddDefaultIdentity
en, så en IUserClaimsPrincipalFactory
implementering kan användas för att lägga till anspråk i identiteten efter en lyckad inloggning.
Varning
Den här artikeln visar användningen av anslutningssträngar. Med en lokal databas behöver användaren inte autentiseras, men i produktion innehåller anslutningssträngar ibland ett lösenord för att autentisera. En resursägares lösenordsautentiseringsuppgifter (ROPC) är en säkerhetsrisk som bör undvikas i produktionsdatabaser. Produktionsappar bör använda det säkraste tillgängliga autentiseringsflödet. Mer information om autentisering för appar som distribueras till test- eller produktionsmiljöer finns i Säkra autentiseringsflöden.
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(
Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
builder.Services.AddSingleton<IEmailSender, EmailSender>();
builder.Services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>,
AdditionalUserClaimsPrincipalFactory>();
builder.Services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled", x => x.RequireClaim("amr", "mfa")));
builder.Services.AddRazorPages();
Klassen AdditionalUserClaimsPrincipalFactory
lägger till amr
anspråk till användaranspråken först efter en lyckad inloggning. Anspråkets värde lästs från databasen. Anspråket läggs till här eftersom användaren endast ska komma åt den högre skyddade vyn om identiteten har loggat in med MFA. Om databasvyn läss direkt från databasen i stället för att använda anspråket går det att komma åt vyn utan MFA direkt efter att MFA har aktiverats.
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace IdentityStandaloneMfa
{
public class AdditionalUserClaimsPrincipalFactory :
UserClaimsPrincipalFactory<IdentityUser, IdentityRole>
{
public AdditionalUserClaimsPrincipalFactory(
UserManager<IdentityUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
{
var principal = await base.CreateAsync(user);
var identity = (ClaimsIdentity)principal.Identity;
var claims = new List<Claim>();
if (user.TwoFactorEnabled)
{
claims.Add(new Claim("amr", "mfa"));
}
else
{
claims.Add(new Claim("amr", "pwd"));
}
identity.AddClaims(claims);
return principal;
}
}
}
Eftersom Identity tjänstkonfigurationen ändrades i klassen Startup
måste layouterna för Identity uppdateras. Skapa Identity sidor i appen. Definiera layouten i Identity/Account/Manage/_Layout.cshtml
-filen.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Tilldela även layouten för alla hanteringsidor från sidorna markerade med Identity.
@{
Layout = "_Layout.cshtml";
}
Verifiera MFA-kravet på administrationssidan
Administrationssidan Razor verifierar att användaren har loggat in med MFA. I metoden OnGet
används identiteten för att komma åt användaranspråken.
amr
-anspråket kontrolleras för värdet mfa
. Om identiteten saknar det här anspråket eller är false
omdirigeras sidan till Aktivera MFA-sidan. Detta är möjligt eftersom användaren redan har loggat in, men utan MFA.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace IdentityStandaloneMfa
{
public class AdminModel : PageModel
{
public IActionResult OnGet()
{
var claimTwoFactorEnabled =
User.Claims.FirstOrDefault(t => t.Type == "amr");
if (claimTwoFactorEnabled != null &&
"mfa".Equals(claimTwoFactorEnabled.Value))
{
// You logged in with MFA, do the administrative stuff
}
else
{
return Redirect(
"/Identity/Account/Manage/TwoFactorAuthentication");
}
return Page();
}
}
}
Användargränssnittslogik för att växla inloggningsinformation för användare
En auktoriseringsprincip lades till vid start. Policyn kräver att amr
ska ha värdet mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Den här principen kan sedan användas i vyn _Layout
för att visa eller dölja menyn Admin med varningen:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Om identiteten har loggat in med MFA visas menyn Admin utan verktygstipsvarningen. När användaren har loggat in utan MFA visas menyn Admin (inte aktiverad) tillsammans med knappbeskrivningen som informerar användaren (förklara varningen).
@if (SignInManager.IsSignedIn(User))
{
@if ((AuthorizationService.AuthorizeAsync(User, "TwoFactorEnabled")).Result.Succeeded)
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Admin">Admin</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Admin"
id="tooltip-demo"
data-toggle="tooltip"
data-placement="bottom"
title="MFA is NOT enabled. This is required for the Admin Page. If you have activated MFA, then logout, login again.">
Admin (Not Enabled)
</a>
</li>
}
}
Om användaren loggar in utan MFA visas varningen:
Användaren omdirigeras till MFA-aktiveringsvyn när du klickar på länken Admin:
Skicka MFA-inloggningskrav till OpenID Connect-servern
Parametern acr_values
kan användas för att skicka det mfa
nödvändiga värdet från klienten till servern i en autentiseringsbegäran.
Not
Parametern acr_values
måste hanteras på OpenID Connect-servern för att detta ska fungera.
OpenID Connect ASP.NET Core-klient
ASP.NET Core Razor Pages OpenID Connect-klientappen använder AddOpenIdConnect
-metoden för att logga in på OpenID Connect-servern. Parametern acr_values
anges med värdet mfa
och skickas med autentiseringsbegäran.
OpenIdConnectEvents
används för att lägga till detta.
För rekommenderade acr_values
parametervärden, se referensvärden för autentiseringsmetod.
build.Services.AddAuthentication(options =>
{
options.DefaultScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.SignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = "<OpenID Connect server URL>";
options.RequireHttpsMetadata = true;
options.ClientId = "<OpenID Connect client ID>";
options.ClientSecret = "<>";
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.SaveTokens = true;
options.AdditionalAuthorizationParameters.Add("acr_values", "mfa");
});
Exempel på OpenID Connect Duende IdentityServer-server med ASP.NET Core Identity
På OpenID Connect-servern, som implementeras med ASP.NET Core Identity med Razor Pages, skapas en ny sida med namnet ErrorEnable2FA.cshtml
. Vyn:
- Visar om Identity kommer från en app som kräver MFA men användaren inte har aktiverat detta i Identity.
- Informerar användaren och lägger till en länk för att aktivera detta.
@{
ViewData["Title"] = "ErrorEnable2FA";
}
<h1>The client application requires you to have MFA enabled. Enable this, try login again.</h1>
<br />
You can enable MFA to login here:
<br />
<a href="~/Identity/Account/Manage/TwoFactorAuthentication">Enable MFA</a>
I metoden Login
används IIdentityServerInteractionService
-gränssnittsimplementeringen _interaction
för att komma åt parametrarna för OpenID Connect-begäran. Parametern acr_values
används med egenskapen AcrValues
. När klienten skickade detta med mfa
angivet kan detta sedan kontrolleras.
Om MFA krävs och användaren i ASP.NET Core Identity har MFA aktiverat fortsätter inloggningen. När användaren inte har aktiverat någon MFA omdirigeras användaren till den anpassade vyn ErrorEnable2FA.cshtml
. Sedan loggar ASP.NET Core Identity in användaren.
Fido2Store används för att kontrollera om användaren har aktiverat MFA med hjälp av en anpassad FIDO2-tokenprovider.
public async Task<IActionResult> OnPost()
{
// check if we are in the context of an authorization request
var context = await _interaction.GetAuthorizationContextAsync(Input.ReturnUrl);
var requires2Fa = context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;
var user = await _userManager.FindByNameAsync(Input.Username);
if (user != null && !user.TwoFactorEnabled && requires2Fa)
{
return RedirectToPage("/Home/ErrorEnable2FA/Index");
}
// code omitted for brevity
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberLogin, lockoutOnFailure: true);
if (result.Succeeded)
{
// code omitted for brevity
}
if (result.RequiresTwoFactor)
{
var fido2ItemExistsForUser = await _fido2Store.GetCredentialsByUserNameAsync(user.UserName);
if (fido2ItemExistsForUser.Count > 0)
{
return RedirectToPage("/Account/LoginFido2Mfa", new { area = "Identity", Input.ReturnUrl, Input.RememberLogin });
}
return RedirectToPage("/Account/LoginWith2fa", new { area = "Identity", Input.ReturnUrl, RememberMe = Input.RememberLogin });
}
await _events.RaiseAsync(new UserLoginFailureEvent(Input.Username, "invalid credentials", clientId: context?.Client.ClientId));
ModelState.AddModelError(string.Empty, LoginOptions.InvalidCredentialsErrorMessage);
}
// something went wrong, show form with error
await BuildModelAsync(Input.ReturnUrl);
return Page();
}
Om användaren redan är inloggad kan klientappen:
- Validerar fortfarande
amr
anspråket. - Kan konfigurera MFA med en länk till vyn ASP.NET Core Identity.
Tvinga ASP.NET Core OpenID Connect-klienten att kräva MFA
Det här exemplet visar hur en ASP.NET Core Razor Page-app, som använder OpenID Connect för att logga in, kan kräva att användarna har autentiserats med hjälp av MFA.
För att verifiera MFA-kravet skapas ett IAuthorizationRequirement
krav. Detta läggs till på sidorna med hjälp av en policy som kräver MFA.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
En AuthorizationHandler
implementeras som använder amr
-anspråket och söker efter värdet mfa
.
amr
returneras i id_token
av en lyckad autentisering och kan ha många olika värden enligt definitionen i referensvärden för -autentiseringsmetod specifikation.
Det returnerade värdet beror på hur identiteten autentiserades och på OpenID Connect-serverimplementeringen.
AuthorizationHandler
använder RequireMfa
-kravet och verifierar amr
-anspråket. OpenID Connect-servern kan implementeras genom att använda Duende Identity server med ASP.NET Core Identity. När en användare loggar in med TOTP returneras amr
-anspråket med ett MFA-värde. Om du använder en annan implementering av OpenID Connect-server eller en annan typ av MFA, kan amr
-kravet ha ett annat värde. Koden måste utökas för att även acceptera detta.
public class RequireMfaHandler : AuthorizationHandler<RequireMfa>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
RequireMfa requirement)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (requirement == null)
throw new ArgumentNullException(nameof(requirement));
var amrClaim =
context.User.Claims.FirstOrDefault(t => t.Type == "amr");
if (amrClaim != null && amrClaim.Value == Amr.Mfa)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
I programfilen används metoden AddOpenIdConnect
som standardschema för utmaning. Auktoriseringshanteraren, som används för att kontrollera amr
krav, läggs till i kontrollinversionscontainern. En princip skapas sedan som lägger till kravet på RequireMfa
.
builder.Services.ConfigureApplicationCookie(options =>
options.Cookie.SecurePolicy =
CookieSecurePolicy.Always);
builder.Services.AddSingleton<IAuthorizationHandler, RequireMfaHandler>();
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.SignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = "https://localhost:44352";
options.RequireHttpsMetadata = true;
options.ClientId = "AspNetCoreRequireMfaOidc";
options.ClientSecret = "AspNetCoreRequireMfaOidcSecret";
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.SaveTokens = true;
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequireMfa", policyIsAdminRequirement =>
{
policyIsAdminRequirement.Requirements.Add(new RequireMfa());
});
});
builder.Services.AddRazorPages();
Den här principen används sedan på sidan Razor efter behov. Principen kan också läggas till globalt för hela appen.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Om användaren loggar in utan MFA kommer amr
-kravet förmodligen att ha ett pwd
-värde. Begäran kommer inte att godkännas för att komma åt sidan. Med standardvärdena omdirigeras användaren till sidan Konto/AccessDenied. Det här beteendet kan ändras eller så kan du implementera din egen anpassade logik här. I det här exemplet läggs en länk till så att den giltiga användaren kan konfigurera MFA för sitt konto.
@page
@model AspNetCoreRequireMfaOidc.AccessDeniedModel
@{
ViewData["Title"] = "AccessDenied";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<h1>AccessDenied</h1>
You require MFA to login here
<a href="https://localhost:44352/Manage/TwoFactorAuthentication">Enable MFA</a>
Nu kan endast användare som autentiserar med MFA komma åt sidan eller webbplatsen. Om olika MFA-typer används eller om 2FA är godkänt, har amr
anspråk olika värden och måste bearbetas korrekt. Olika OpenID Connect-servrar returnerar också olika värden för det här anspråket och kanske inte följer referensvärdena för autentiseringsmetod specifikationen.
När du loggar in utan MFA (till exempel med bara ett lösenord):
amr
har värdetpwd
:Åtkomst nekas:
Alternativt logga in med OTP via Identity:
OIDC- och OAuth-parameteranpassning
Alternativet OAuth- och OIDC-autentiseringshanterare AdditionalAuthorizationParameters tillåter anpassning av auktoriseringsmeddelandeparametrar som vanligtvis ingår som en del av omdirigeringsfrågesträngen:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Ytterligare resurser
Visa eller ladda ned exempelkod (damienbod/AspNetCoreHybridFlowWithApi GitHub-lagringsplats)
Multifaktorautentisering (MFA) är en process där en användare begärs under en inloggningshändelse för ytterligare former av identifiering. Den här uppmaningen kan vara att ange en kod från en mobiltelefon, använda en FIDO2-nyckel eller att tillhandahålla en fingeravtrycksgenomsökning. När du behöver en andra form av autentisering förbättras säkerheten. Den ytterligare faktorn är inte lätt att utvinnas eller dupliceras av en cyberattack.
Den här artikeln beskriver följande områden:
- Vad är MFA och vilka MFA-flöden som rekommenderas
- Konfigurera MFA för administrationssidor med hjälp av ASP.NET Core Identity
- Skicka MFA-inloggningskrav till OpenID Connect-servern
- Tvinga ASP.NET Core OpenID Connect-klienten att kräva MFA
Multi-Faktor Autentisering (MFA), Tvåfaktorautentisering (2FA)
MFA kräver minst två eller flera typer av bevis för en identitet som något du vet, något du har eller biometrisk validering för att användaren ska kunna autentisera.
Tvåfaktorautentisering (2FA) är som en delmängd av MFA, men skillnaden är att MFA kan kräva två eller flera faktorer för att bevisa identiteten.
2FA stöds som standard när du använder ASP.NET Core Identity. Om du vill aktivera eller inaktivera 2FA för en viss användare anger du egenskapen IdentityUser<TKey>.TwoFactorEnabled. Standardgränssnittet för ASP.NET Core Identity innehåller sidor för att konfigurera 2FA.
MFA TOTP (tidsbaserad engångslösenordalgoritm)
MFA med TOTP stöds som standard när du använder ASP.NET Core Identity. Den här metoden kan användas tillsammans med alla kompatibla autentiseringsappar, inklusive:
- Microsoft Authenticator
- Google Authenticator
Mer information om implementering finns i Aktivera QR Code-generering för TOTP-autentiseringsappar i ASP.NET Core.
Om du vill inaktivera stöd för MFA TOTP konfigurerar du autentisering med AddIdentity i stället för AddDefaultIdentity.
AddDefaultIdentity
anropar AddDefaultTokenProviders internt, vilket registrerar flera tokenprovidrar, inklusive en för MFA TOTP. Om du bara vill registrera specifika tokenprovidrar anropar du AddTokenProvider för varje obligatorisk provider. Mer information om tillgängliga tokenprovidrar finns i källan AddDefaultTokenProviders på GitHub.
MFA-passerkoder/FIDO2 eller lösenordsfri
passkeys/FIDO2 är för närvarande:
- Det säkraste sättet att uppnå MFA.
- MFA som förebygger phishing-attacker. (Förutom certifikatautentisering och Windows för företag)
För närvarande stöder ASP.NET Core inte passerkoder/FIDO2 direkt. Lösenord/FIDO2 kan användas för MFA- eller lösenordslösa flöden.
Microsoft Entra ID ger stöd för nyckellösa autentiseringsmetoder som FIDO2 och lösenordslösa flöden. Mer information finns i alternativ för lösenordsfri autentisering.
Andra former av lösenordslös MFA kan eventuellt inte skydda mot nätfiske.
Multifaktorsautentisering SMS
MFA med SMS ökar säkerheten kraftigt jämfört med lösenordsautentisering (enskild faktor). Att använda SMS som en andra faktor rekommenderas dock inte längre. Det finns för många kända attackvektorer för den här typen av implementering.
Konfigurera MFA för administrationssidor med hjälp av ASP.NET Core Identity
MFA kan behöva krävas av användare för att komma åt känsliga sidor i en ASP.NET Core Identity-app. Detta kan vara användbart för appar där det finns olika åtkomstnivåer för de olika identiteterna. Användare kanske till exempel kan visa profildata med hjälp av en lösenordsinloggning, men en administratör måste använda MFA för att få åtkomst till de administrativa sidorna.
Utöka inloggningen med ett MFA-anspråk
Demokoden konfigureras med hjälp av ASP.NET Core med Identity och Razor Pages. Metoden AddIdentity
används i stället för AddDefaultIdentity
en, så en IUserClaimsPrincipalFactory
implementering kan användas för att lägga till anspråk i identiteten efter en lyckad inloggning.
Varning
Den här artikeln visar användningen av anslutningssträngar. Med en lokal databas behöver användaren inte autentiseras, men i produktion innehåller anslutningssträngar ibland ett lösenord för att autentisera. En resursägares lösenordsautentiseringsuppgifter (ROPC) är en säkerhetsrisk som bör undvikas i produktionsdatabaser. Produktionsappar bör använda det säkraste tillgängliga autentiseringsflödet. Mer information om autentisering för appar som distribueras till test- eller produktionsmiljöer finns i Säkra autentiseringsflöden.
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(
Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
builder.Services.AddSingleton<IEmailSender, EmailSender>();
builder.Services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>,
AdditionalUserClaimsPrincipalFactory>();
builder.Services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled", x => x.RequireClaim("amr", "mfa")));
builder.Services.AddRazorPages();
Klassen AdditionalUserClaimsPrincipalFactory
lägger till amr
till användarens anspråk först efter en lyckad inloggning. Anspråkets värde läses från databasen. Anspråket läggs till här eftersom användaren endast ska komma åt den högre skyddade vyn om identiteten har loggat in med MFA. Om databasvyn läss direkt från databasen i stället för att använda anspråket går det att komma åt vyn utan MFA direkt efter att MFA har aktiverats.
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace IdentityStandaloneMfa
{
public class AdditionalUserClaimsPrincipalFactory :
UserClaimsPrincipalFactory<IdentityUser, IdentityRole>
{
public AdditionalUserClaimsPrincipalFactory(
UserManager<IdentityUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
{
var principal = await base.CreateAsync(user);
var identity = (ClaimsIdentity)principal.Identity;
var claims = new List<Claim>();
if (user.TwoFactorEnabled)
{
claims.Add(new Claim("amr", "mfa"));
}
else
{
claims.Add(new Claim("amr", "pwd"));
}
identity.AddClaims(claims);
return principal;
}
}
}
Eftersom Identity tjänstkonfigurationen ändrades i klassen Startup
måste layouterna för Identity uppdateras. Strukturera Identity sidorna i appen. Definiera layouten i Identity/Account/Manage/_Layout.cshtml
-filen.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Tilldela även layouten för alla administrationssidor från sidorna Identity.
@{
Layout = "_Layout.cshtml";
}
Verifiera MFA-kravet på administrationssidan
Administrationssidan Razor verifierar att användaren har loggat in med MFA. I metoden OnGet
används identiteten för att komma åt användaranspråken. Anspråket amr
kontrolleras för värdet mfa
. Om identiteten saknar detta påstående eller är false
, omdirigeras sidan till Aktivera MFA-sidan. Detta är möjligt eftersom användaren redan har loggat in, men utan MFA.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace IdentityStandaloneMfa
{
public class AdminModel : PageModel
{
public IActionResult OnGet()
{
var claimTwoFactorEnabled =
User.Claims.FirstOrDefault(t => t.Type == "amr");
if (claimTwoFactorEnabled != null &&
"mfa".Equals(claimTwoFactorEnabled.Value))
{
// You logged in with MFA, do the administrative stuff
}
else
{
return Redirect(
"/Identity/Account/Manage/TwoFactorAuthentication");
}
return Page();
}
}
}
Användargränssnittslogik för att växla inloggningsinformation för användare
En auktoriseringsprincip lades till vid start. Policyn föreskriver amr
-anspråket med värdet mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Den här principen kan sedan användas i vyn _Layout
för att visa eller dölja menyn Admin med varningen:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Om identiteten har loggat in med MFA visas menyn Admin utan verktygstipsvarningen. När användaren har loggat in utan MFA visas menyn Admin (inte aktiverad) tillsammans med knappbeskrivningen som informerar användaren (förklara varningen).
@if (SignInManager.IsSignedIn(User))
{
@if ((AuthorizationService.AuthorizeAsync(User, "TwoFactorEnabled")).Result.Succeeded)
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Admin">Admin</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Admin"
id="tooltip-demo"
data-toggle="tooltip"
data-placement="bottom"
title="MFA is NOT enabled. This is required for the Admin Page. If you have activated MFA, then logout, login again.">
Admin (Not Enabled)
</a>
</li>
}
}
Om användaren loggar in utan MFA visas varningen:
Användaren omdirigeras till MFA-aktiveringsvyn när du klickar på länken Admin:
Skicka MFA-inloggningskrav till OpenID Connect-servern
Parametern acr_values
kan användas för att skicka det mfa
nödvändiga värdet från klienten till servern i en autentiseringsbegäran.
Anteckning
Parametern acr_values
måste hanteras på OpenID Connect-servern för att detta ska fungera.
OpenID Connect ASP.NET Core-klient
ASP.NET Core Razor Pages OpenID Connect-klientappen använder AddOpenIdConnect
-metoden för att logga in på OpenID Connect-servern. Parametern acr_values
anges med värdet mfa
och skickas med autentiseringsbegäran. Det OpenIdConnectEvents
används för att lägga till detta.
För rekommenderade parametervärden för acr_values
, se Autentiseringsmetodens referensvärden .
build.Services.AddAuthentication(options =>
{
options.DefaultScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.SignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = "<OpenID Connect server URL>";
options.RequireHttpsMetadata = true;
options.ClientId = "<OpenID Connect client ID>";
options.ClientSecret = "<>";
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("acr_values", "mfa");
return Task.FromResult(0);
}
};
});
Exempel på OpenID Connect Duende IdentityServer-server med ASP.NET Core Identity
På OpenID Connect-servern, som implementeras med ASP.NET Core Identity med Razor Pages, skapas en ny sida med namnet ErrorEnable2FA.cshtml
. Vy:
- Visar om Identity kommer från en app som kräver MFA men användaren inte har aktiverat detta i Identity.
- Informerar användaren och lägger till en länk för att aktivera detta.
@{
ViewData["Title"] = "ErrorEnable2FA";
}
<h1>The client application requires you to have MFA enabled. Enable this, try login again.</h1>
<br />
You can enable MFA to login here:
<br />
<a href="~/Identity/Account/Manage/TwoFactorAuthentication">Enable MFA</a>
I metoden Login
används IIdentityServerInteractionService
-gränssnittsimplementeringen _interaction
för att komma åt parametrarna för OpenID Connect-begäran. Parametern acr_values
används med egenskapen AcrValues
. När klienten skickade detta med mfa
angivet kan detta sedan kontrolleras.
Om MFA krävs och användaren i ASP.NET Core Identity har MFA aktiverat fortsätter inloggningen. När användaren inte har aktiverat någon MFA omdirigeras användaren till den anpassade vyn ErrorEnable2FA.cshtml
. Sedan loggar ASP.NET Core Identity in användaren.
Fido2Store används för att kontrollera om användaren har aktiverat MFA med hjälp av en anpassad FIDO2-tokenprovider.
public async Task<IActionResult> OnPost()
{
// check if we are in the context of an authorization request
var context = await _interaction.GetAuthorizationContextAsync(Input.ReturnUrl);
var requires2Fa = context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;
var user = await _userManager.FindByNameAsync(Input.Username);
if (user != null && !user.TwoFactorEnabled && requires2Fa)
{
return RedirectToPage("/Home/ErrorEnable2FA/Index");
}
// code omitted for brevity
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberLogin, lockoutOnFailure: true);
if (result.Succeeded)
{
// code omitted for brevity
}
if (result.RequiresTwoFactor)
{
var fido2ItemExistsForUser = await _fido2Store.GetCredentialsByUserNameAsync(user.UserName);
if (fido2ItemExistsForUser.Count > 0)
{
return RedirectToPage("/Account/LoginFido2Mfa", new { area = "Identity", Input.ReturnUrl, Input.RememberLogin });
}
return RedirectToPage("/Account/LoginWith2fa", new { area = "Identity", Input.ReturnUrl, RememberMe = Input.RememberLogin });
}
await _events.RaiseAsync(new UserLoginFailureEvent(Input.Username, "invalid credentials", clientId: context?.Client.ClientId));
ModelState.AddModelError(string.Empty, LoginOptions.InvalidCredentialsErrorMessage);
}
// something went wrong, show form with error
await BuildModelAsync(Input.ReturnUrl);
return Page();
}
Om användaren redan är inloggad kan klientappen:
- Bekräftar fortfarande
amr
-kravet. - Kan konfigurera MFA med en länk till vyn ASP.NET Core Identity.
Tvinga ASP.NET Core OpenID Connect-klienten att kräva MFA
Det här exemplet visar hur en ASP.NET Core Razor Page-app, som använder OpenID Connect för att logga in, kan kräva att användarna har autentiserats med hjälp av MFA.
För att verifiera MFA-kravet skapas ett IAuthorizationRequirement
krav. Detta kommer att läggas till på sidorna med hjälp av en policy som kräver MFA.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
En AuthorizationHandler
implementeras som använder amr
-anspråket och söker efter värdet mfa
.
amr
returneras i id_token
av en lyckad autentisering och kan ha många olika värden enligt definitionen i referensvärden för -autentiseringsmetod specifikation.
Det returnerade värdet beror på hur identiteten autentiserades och på OpenID Connect-serverimplementeringen.
AuthorizationHandler
använder RequireMfa
-kravet och validerar amr
-anspråket. OpenID Connect-servern kan implementeras genom att använda Duende Identity Server och ASP.NET Core Identity. När en användare loggar in med TOTP returneras begäran amr
med värdet MFA. Om du använder en annan OpenID Connect-serverimplementering eller en annan MFA-typ kan amr
-anspråket eller kommer att ha ett annat värde. Koden måste utökas för att även acceptera detta.
public class RequireMfaHandler : AuthorizationHandler<RequireMfa>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
RequireMfa requirement)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (requirement == null)
throw new ArgumentNullException(nameof(requirement));
var amrClaim =
context.User.Claims.FirstOrDefault(t => t.Type == "amr");
if (amrClaim != null && amrClaim.Value == Amr.Mfa)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
I programfilen används metoden AddOpenIdConnect
som standardschema för utmaning. Auktoriseringshanteraren, som används för att kontrollera amr
anspråk, läggs till i Inversion of Control-containern. En princip skapas sedan som lägger till kravet på RequireMfa
.
builder.Services.ConfigureApplicationCookie(options =>
options.Cookie.SecurePolicy =
CookieSecurePolicy.Always);
builder.Services.AddSingleton<IAuthorizationHandler, RequireMfaHandler>();
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.SignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = "https://localhost:44352";
options.RequireHttpsMetadata = true;
options.ClientId = "AspNetCoreRequireMfaOidc";
options.ClientSecret = "AspNetCoreRequireMfaOidcSecret";
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.SaveTokens = true;
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequireMfa", policyIsAdminRequirement =>
{
policyIsAdminRequirement.Requirements.Add(new RequireMfa());
});
});
builder.Services.AddRazorPages();
Den här principen används sedan på sidan Razor efter behov. Principen kan också läggas till globalt för hela appen.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Om användaren autentiserar utan MFA kommer amr
-anspråket förmodligen att ha ett pwd
-värde. Begäran kommer inte att auktoriseras att komma åt sidan. Med standardvärdena omdirigeras användaren till sidan Konto/AccessDenied. Det här beteendet kan ändras eller så kan du implementera din egen anpassade logik här. I det här exemplet läggs en länk till så att den giltiga användaren kan konfigurera MFA för sitt konto.
@page
@model AspNetCoreRequireMfaOidc.AccessDeniedModel
@{
ViewData["Title"] = "AccessDenied";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<h1>AccessDenied</h1>
You require MFA to login here
<a href="https://localhost:44352/Manage/TwoFactorAuthentication">Enable MFA</a>
Nu kan endast användare som autentiserar med MFA komma åt sidan eller webbplatsen. Om olika typer av MFA används eller om 2FA är godkänt kommer amr
-anspråket ha olika värden och behöver bearbetas korrekt. Olika OpenID Connect-servrar returnerar också olika värden för det här anspråket och kanske inte följer referensvärdena för autentiseringsmetod specifikationen.
När du loggar in utan MFA (till exempel med bara ett lösenord):
amr
har värdetpwd
:Åtkomst nekas:
Alternativt kan du logga in med OTP Identity:
Ytterligare resurser
Visa eller ladda ned exempelkod (damienbod/AspNetCoreHybridFlowWithApi GitHub-lagringsplats)
Multifaktorautentisering (MFA) är en process där en användare begärs under en inloggningshändelse för ytterligare former av identifiering. Den här uppmaningen kan vara att ange en kod från en mobiltelefon, använda en FIDO2-nyckel eller att tillhandahålla en fingeravtrycksgenomsökning. När du behöver en andra form av autentisering förbättras säkerheten. Den ytterligare faktorn är inte lätt att erhålla eller duplicera av en cyberattackare.
Den här artikeln beskriver följande områden:
- Vad är MFA och vilka MFA-flöden som rekommenderas
- Konfigurera MFA för administrationssidor med hjälp av ASP.NET Core Identity
- Skicka MFA-inloggningskrav till OpenID Connect-servern
- Tvinga ASP.NET Core OpenID Connect-klienten att kräva MFA
MFA, 2FA
MFA kräver minst två eller flera typer av bevis för en identitet som något du vet, något du har eller biometrisk validering för att användaren ska kunna autentisera.
Tvåfaktorautentisering (2FA) är som en delmängd av MFA, men skillnaden är att MFA kan kräva två eller flera faktorer för att bevisa identiteten.
MFA TOTP (tidsbaserad engångslösenordalgoritm)
MFA med TOTP är en implementering som stöds med ASP.NET Core Identity. Detta kan användas tillsammans med alla kompatibla autentiseringsappar, inklusive:
- Microsoft Authenticator app
- Google Authenticatorapp
Se följande länk för implementeringsinformation:
Aktivera QR Code-generering för TOTP-autentiseringsappar i ASP.NET Core
MFA-passnycklar/FIDO2 eller utan lösenord
passkeys/FIDO2 är för närvarande:
- Det säkraste sättet att uppnå MFA.
- MFA som skyddar mot nätfiskeattacker. (Förutom certifikatautentisering och Windows för företag)
För närvarande stöder ASP.NET Core inte lösenordsnycklar/FIDO2 direkt. Lösenord/FIDO2 kan användas för MFA- eller lösenordslösa flöden.
Microsoft Entra ID ger stöd för passkeys/FIDO2 och lösenordslösa flöden. Mer information finns i alternativ för lösenordsfri autentisering.
Andra former av lösenordslös MFA skyddar eventuellt inte mot nätfiske.
SMS för multifaktorsautentisering
MFA med SMS ökar säkerheten kraftigt jämfört med lösenordsautentisering (enskild faktor). Att använda SMS som en andra faktor rekommenderas dock inte längre. Det finns för många kända attackvektorer för den här typen av implementering.
Konfigurera MFA för administrationssidor med hjälp av ASP.NET Core Identity
MFA kan krävas av användare för att komma åt känsliga sidor i en ASP.NET Core Identity-app. Detta kan vara användbart för appar där det finns olika åtkomstnivåer för de olika identiteterna. Användare kanske till exempel kan visa profildata med hjälp av en lösenordsinloggning, men en administratör måste använda MFA för att få åtkomst till de administrativa sidorna.
Utöka inloggningen med ett MFA-anspråk
Demokoden konfigureras med hjälp av ASP.NET Core med Identity och Razor Pages. Metoden AddIdentity
används i stället för AddDefaultIdentity
en, så en IUserClaimsPrincipalFactory
implementering kan användas för att lägga till anspråk i identiteten efter en lyckad inloggning.
Varning
Den här artikeln visar användningen av anslutningssträngar. Med en lokal databas behöver användaren inte autentiseras, men i produktion innehåller anslutningssträngar ibland ett lösenord för att autentisera. En resursägares lösenordsautentiseringsuppgifter (ROPC) är en säkerhetsrisk som bör undvikas i produktionsdatabaser. Produktionsappar bör använda det säkraste tillgängliga autentiseringsflödet. Mer information om autentisering för appar som distribueras till test- eller produktionsmiljöer finns i Säkra autentiseringsflöden.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<IdentityUser, IdentityRole>(
options => options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddSingleton<IEmailSender, EmailSender>();
services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>,
AdditionalUserClaimsPrincipalFactory>();
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
services.AddRazorPages();
}
Klassen AdditionalUserClaimsPrincipalFactory
lägger till amr
anspråk till användaranspråken först efter en lyckad inloggning. Anspråkets värde läses från databasen. Anspråket läggs till här eftersom användaren endast ska komma åt den högre skyddade vyn om identiteten har loggat in med MFA. Om databasvyn läss direkt från databasen i stället för att använda anspråket går det att komma åt vyn utan MFA direkt efter att MFA har aktiverats.
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace IdentityStandaloneMfa
{
public class AdditionalUserClaimsPrincipalFactory :
UserClaimsPrincipalFactory<IdentityUser, IdentityRole>
{
public AdditionalUserClaimsPrincipalFactory(
UserManager<IdentityUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
{
var principal = await base.CreateAsync(user);
var identity = (ClaimsIdentity)principal.Identity;
var claims = new List<Claim>();
if (user.TwoFactorEnabled)
{
claims.Add(new Claim("amr", "mfa"));
}
else
{
claims.Add(new Claim("amr", "pwd"));
}
identity.AddClaims(claims);
return principal;
}
}
}
Eftersom Identity tjänstkonfigurationen ändrades i klassen Startup
måste layouterna för Identity uppdateras. Skapa Identity sidor i appen. Definiera layouten i Identity/Account/Manage/_Layout.cshtml
-filen.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Tilldela layouten även för alla administrationssidor från Identity-sidor:
@{
Layout = "_Layout.cshtml";
}
Verifiera MFA-kravet på administrationssidan
Administrationssidan Razor verifierar att användaren har loggat in med MFA. I metoden OnGet
används identiteten för att komma åt användaranspråken. Kravet amr
kontrolleras för värdet mfa
. Om identiteten saknar det här anspråket eller är false
omdirigeras sidan till sidan Aktivera MFA. Detta är möjligt eftersom användaren redan har loggat in, men utan MFA.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace IdentityStandaloneMfa
{
public class AdminModel : PageModel
{
public IActionResult OnGet()
{
var claimTwoFactorEnabled =
User.Claims.FirstOrDefault(t => t.Type == "amr");
if (claimTwoFactorEnabled != null &&
"mfa".Equals(claimTwoFactorEnabled.Value))
{
// You logged in with MFA, do the administrative stuff
}
else
{
return Redirect(
"/Identity/Account/Manage/TwoFactorAuthentication");
}
return Page();
}
}
}
Användargränssnittslogik för att växla inloggningsinformation för användare
En auktoriseringsprincip lades till i programfilen. Policyn kräver amr
-anspråk med värdet mfa
.
builder.Services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Den här principen kan sedan användas i vyn _Layout
för att visa eller dölja menyn Admin med varningen:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Om identiteten har loggat in med MFA visas menyn Admin utan varningen om verktygstips. När användaren har loggat in utan MFA visas menyn Admin (inte aktiverad) tillsammans med knappbeskrivningen som informerar användaren (förklara varningen).
@if (SignInManager.IsSignedIn(User))
{
@if ((AuthorizationService.AuthorizeAsync(User, "TwoFactorEnabled")).Result.Succeeded)
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Admin">Admin</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Admin"
id="tooltip-demo"
data-toggle="tooltip"
data-placement="bottom"
title="MFA is NOT enabled. This is required for the Admin Page. If you have activated MFA, then logout, login again.">
Admin (Not Enabled)
</a>
</li>
}
}
Om användaren loggar in utan MFA visas varningen:
Användaren omdirigeras till MFA-aktiveringsvyn när du klickar på länken Admin:
Skicka MFA-inloggningskrav till OpenID Connect-servern
Parametern acr_values
kan användas för att skicka det mfa
nödvändiga värdet från klienten till servern i en autentiseringsbegäran.
Obs
Parametern acr_values
måste hanteras på OpenID Connect-servern för att detta ska fungera.
OpenID Connect ASP.NET Core-klient
ASP.NET Core Razor Pages OpenID Connect-klientappen använder AddOpenIdConnect
-metoden för att logga in på OpenID Connect-servern. Parametern acr_values
anges med värdet mfa
och skickas med autentiseringsbegäran.
OpenIdConnectEvents
används för att lägga till detta.
För rekommenderade acr_values
-parametervärden, se referensvärden för autentiseringsmetoden .
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.SignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = "<OpenID Connect server URL>";
options.RequireHttpsMetadata = true;
options.ClientId = "<OpenID Connect client ID>";
options.ClientSecret = "<>";
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("acr_values", "mfa");
return Task.FromResult(0);
}
};
});
Exempel på OpenID Connect IdentityServer 4-server med ASP.NET Core Identity
På OpenID Connect-servern, som implementeras med ASP.NET Core Identity med MVC-vyer, skapas en ny vy med namnet ErrorEnable2FA.cshtml
. Vyn:
- Visar om Identity kommer från en app som kräver MFA men användaren inte har aktiverat detta i Identity.
- Informerar användaren och lägger till en länk för att aktivera detta.
@{
ViewData["Title"] = "ErrorEnable2FA";
}
<h1>The client application requires you to have MFA enabled. Enable this, try login again.</h1>
<br />
You can enable MFA to login here:
<br />
<a asp-controller="Manage" asp-action="TwoFactorAuthentication">Enable MFA</a>
I metoden Login
används IIdentityServerInteractionService
-gränssnittsimplementeringen _interaction
för att komma åt parametrarna för OpenID Connect-begäran. Parametern acr_values
används med egenskapen AcrValues
. När klienten skickade detta med mfa
angivet kan detta sedan kontrolleras.
Om MFA krävs och användaren i ASP.NET Core Identity har MFA aktiverat fortsätter inloggningen. När användaren inte har aktiverat någon MFA omdirigeras användaren till den anpassade vyn ErrorEnable2FA.cshtml
. Sedan loggar ASP.NET Core Identity in användaren.
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginInputModel model)
{
var returnUrl = model.ReturnUrl;
var context =
await _interaction.GetAuthorizationContextAsync(returnUrl);
var requires2Fa =
context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;
var user = await _userManager.FindByNameAsync(model.Email);
if (user != null && !user.TwoFactorEnabled && requires2Fa)
{
return RedirectToAction(nameof(ErrorEnable2FA));
}
// code omitted for brevity
Metoden ExternalLoginCallback
fungerar som den lokala Identity inloggningen. Egenskapen AcrValues
kontrolleras för värdet mfa
. Om mfa
-värdet finns tvingas MFA göras innan inloggningen är klar (till exempel omdirigerad till vyn ErrorEnable2FA
).
//
// GET: /Account/ExternalLoginCallback
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(
string returnUrl = null,
string remoteError = null)
{
var context =
await _interaction.GetAuthorizationContextAsync(returnUrl);
var requires2Fa =
context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;
if (remoteError != null)
{
ModelState.AddModelError(
string.Empty,
_sharedLocalizer["EXTERNAL_PROVIDER_ERROR",
remoteError]);
return View(nameof(Login));
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(Login));
}
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
if (!string.IsNullOrEmpty(email))
{
var user = await _userManager.FindByNameAsync(email);
if (user != null && !user.TwoFactorEnabled && requires2Fa)
{
return RedirectToAction(nameof(ErrorEnable2FA));
}
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager
.ExternalLoginSignInAsync(
info.LoginProvider,
info.ProviderKey,
isPersistent:
false);
// code omitted for brevity
Om användaren redan är inloggad kan klientappen:
- Validerar fortfarande
amr
anspråket. - Kan konfigurera MFA med en länk till vyn ASP.NET Core Identity.
Tvinga ASP.NET Core OpenID Connect-klienten att kräva MFA
Det här exemplet visar hur en ASP.NET Core Razor Page-app, som använder OpenID Connect för att logga in, kan kräva att användarna har autentiserats med hjälp av MFA.
För att verifiera MFA-kravet skapas ett IAuthorizationRequirement
krav. Detta läggs till på sidorna med hjälp av en policy som kräver multifaktorsautentisering.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc
{
public class RequireMfa : IAuthorizationRequirement{}
}
En AuthorizationHandler
implementeras som använder amr
-anspråket och söker efter värdet mfa
.
amr
returneras i id_token
av en lyckad autentisering och kan ha många olika värden enligt definitionen i referensvärden för -autentiseringsmetod specifikation.
Det returnerade värdet beror på hur identiteten autentiserades och på OpenID Connect-serverimplementeringen.
AuthorizationHandler
använder kravet på RequireMfa
och bekräftar amr
anspråk. OpenID Connect-servern kan implementeras med IdentityServer4 med ASP.NET Core Identity. När en användare loggar in med TOTP returneras anspråket amr
med ett MFA-värde. Om du använder en annan OpenID Connect-serverimplementering eller en annan MFA-typ kan amr
-anspråket ha ett annat värde. Koden måste utökas för att även acceptera detta.
public class RequireMfaHandler : AuthorizationHandler<RequireMfa>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
RequireMfa requirement)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (requirement == null)
throw new ArgumentNullException(nameof(requirement));
var amrClaim =
context.User.Claims.FirstOrDefault(t => t.Type == "amr");
if (amrClaim != null && amrClaim.Value == Amr.Mfa)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
I metoden Startup.ConfigureServices
används AddOpenIdConnect
-metoden som standardschema för utmaning. Auktoriseringshanteraren, som används för att kontrollera amr
anspråk, läggs till i containern Inversion av Control. En princip skapas sedan som lägger till kravet på RequireMfa
.
public void ConfigureServices(IServiceCollection services)
{
services.ConfigureApplicationCookie(options =>
options.Cookie.SecurePolicy =
CookieSecurePolicy.Always);
services.AddSingleton<IAuthorizationHandler, RequireMfaHandler>();
services.AddAuthentication(options =>
{
options.DefaultScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.SignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = "https://localhost:44352";
options.RequireHttpsMetadata = true;
options.ClientId = "AspNetCoreRequireMfaOidc";
options.ClientSecret = "AspNetCoreRequireMfaOidcSecret";
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.SaveTokens = true;
});
services.AddAuthorization(options =>
{
options.AddPolicy("RequireMfa", policyIsAdminRequirement =>
{
policyIsAdminRequirement.Requirements.Add(new RequireMfa());
});
});
services.AddRazorPages();
}
Den här principen används sedan på sidan Razor efter behov. Principen kan också läggas till globalt för hela appen.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Om användaren autentiserar sig utan MFA har amr
-anspråket förmodligen ett pwd
-värde. Begäran kommer inte att tillåtas att få åtkomst till sidan. Med standardvärdena omdirigeras användaren till sidan Konto/AccessDenied. Det här beteendet kan ändras eller så kan du implementera din egen anpassade logik här. I det här exemplet läggs en länk till så att den giltiga användaren kan konfigurera MFA för sitt konto.
@page
@model AspNetCoreRequireMfaOidc.AccessDeniedModel
@{
ViewData["Title"] = "AccessDenied";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<h1>AccessDenied</h1>
You require MFA to login here
<a href="https://localhost:44352/Manage/TwoFactorAuthentication">Enable MFA</a>
Nu kan endast användare som autentiserar med MFA komma åt sidan eller webbplatsen. Om olika MFA-typer används eller om 2FA är tillåten, har amr
krav olika värden och måste bearbetas korrekt. Olika OpenID Connect-servrar returnerar också olika värden för det här anspråket och kanske inte följer referensvärdena för autentiseringsmetod specifikationen.
När du loggar in utan MFA (till exempel med bara ett lösenord):
amr
har värdetpwd
.Åtkomst nekas:
Du kan också logga in med hjälp av OTP Identity:
Ytterligare resurser
ASP.NET Core