Autentikasi multifaktor di ASP.NET Core
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Oleh Damien Bowden
Melihat atau mengunduh kode sampel (repositori GitHub damienbod/AspNetCoreHybridFlowWithApi)
Autentikasi multifaktor (MFA) adalah proses di mana pengguna diminta selama peristiwa masuk untuk bentuk identifikasi tambahan. Perintah ini bisa untuk memasukkan kode dari ponsel, menggunakan kunci FIDO2, atau untuk memberikan pemindaian sidik jari. Ketika Anda memerlukan bentuk autentikasi kedua, keamanan ditingkatkan. Faktor tambahan tidak mudah diperoleh atau diduplikasi oleh serangan cyber.
Artikel ini membahas area berikut:
- Apa itu MFA dan alur MFA apa yang direkomendasikan
- Mengonfigurasi MFA untuk halaman administrasi menggunakan ASP.NET Core Identity
- Mengirim persyaratan masuk MFA ke server OpenID Connect
- Paksa ASP.NET klien Core OpenID Connect untuk mewajibkan MFA
MFA, 2FA
MFA memerlukan setidaknya dua atau lebih jenis bukti untuk sesuatu seperti yang identity Anda ketahui, sesuatu yang Anda miliki, atau validasi biometrik bagi pengguna untuk diautentikasi.
Autentikasi dua faktor (2FA) seperti subset MFA, tetapi perbedaannya adalah bahwa MFA dapat memerlukan dua faktor atau lebih untuk membuktikan identity.
2FA didukung secara default saat menggunakan ASP.NET Core Identity. Untuk mengaktifkan atau menonaktifkan 2FA untuk pengguna tertentu, atur IdentityUser<TKey>.TwoFactorEnabled properti . UI Default ASP.NET Core Identity menyertakan halaman untuk mengonfigurasi 2FA.
MFA TOTP (Algoritma Kata Sandi Satu Kali Berbasis Waktu)
MFA yang menggunakan TOTP didukung secara default saat menggunakan ASP.NET Core Identity. Pendekatan ini dapat digunakan bersama dengan aplikasi pengautentikasi yang sesuai, termasuk:
- Microsoft Authenticator
- Google Authenticator
Untuk detail implementasi, lihat Mengaktifkan pembuatan Kode QR untuk aplikasi pengautentikasi TOTP di ASP.NET Core.
Untuk menonaktifkan dukungan untuk MFA TOTP, konfigurasikan autentikasi menggunakan AddIdentity alih-alih AddDefaultIdentity. AddDefaultIdentity
AddDefaultTokenProviders memanggil secara internal, yang mendaftarkan beberapa penyedia token termasuk satu untuk MFA TOTP. Untuk mendaftarkan hanya penyedia token tertentu, panggil AddTokenProvider untuk setiap penyedia yang diperlukan. Untuk informasi selengkapnya tentang penyedia token yang tersedia, lihat sumber AddDefaultTokenProviders di GitHub.
Kode akses MFA/FIDO2 atau tanpa kata sandi
passkeys/FIDO2 saat ini:
- Cara paling aman untuk mencapai MFA.
- MFA yang melindungi dari serangan phishing. (Serta autentikasi sertifikat dan Windows untuk bisnis)
Saat ini, ASP.NET Core tidak mendukung passkeys/FIDO2 secara langsung. Passkeys/FIDO2 dapat digunakan untuk alur MFA atau tanpa kata sandi.
MICROSOFT Entra ID menyediakan dukungan untuk passkeys/FIDO2 dan alur tanpa kata sandi. Untuk informasi selengkapnya, lihat Opsi autentikasi tanpa kata sandi.
Bentuk lain dari MFA tanpa kata sandi tidak atau mungkin tidak melindungi dari phishing.
MFA SMS
MFA dengan SMS meningkatkan keamanan secara besar-besaran dibandingkan dengan autentikasi kata sandi (faktor tunggal). Namun, menggunakan SMS sebagai faktor kedua tidak lagi direkomendasikan. Terlalu banyak vektor serangan yang diketahui ada untuk jenis implementasi ini.
Mengonfigurasi MFA untuk halaman administrasi menggunakan ASP.NET Core Identity
MFA dapat dipaksa pada pengguna untuk mengakses halaman sensitif dalam aplikasi ASP.NET Core Identity . Ini bisa berguna untuk aplikasi di mana berbagai tingkat akses ada untuk identitas yang berbeda. Misalnya, pengguna mungkin dapat melihat data profil menggunakan login kata sandi, tetapi administrator akan diminta untuk menggunakan MFA untuk mengakses halaman administratif.
Memperpanjang login dengan klaim MFA
Kode demo disiapkan menggunakan ASP.NET Core dengan Identity dan Razor Pages. Metode AddIdentity
ini digunakan alih-alih AddDefaultIdentity
satu, sehingga IUserClaimsPrincipalFactory
implementasi dapat digunakan untuk menambahkan klaim ke identity setelah login yang berhasil.
Peringatan
Artikel ini memperlihatkan penggunaan string koneksi. Dengan database lokal, pengguna tidak perlu diautentikasi, tetapi dalam produksi, string koneksi terkadang menyertakan kata sandi untuk mengautentikasi. Kredensial kata sandi pemilik sumber daya (ROPC) adalah risiko keamanan yang harus dihindari dalam database produksi. Aplikasi produksi harus menggunakan alur autentikasi paling aman yang tersedia. Untuk informasi selengkapnya tentang autentikasi untuk aplikasi yang disebarkan untuk menguji atau lingkungan produksi, lihat Mengamankan alur autentikasi.
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();
Kelas AdditionalUserClaimsPrincipalFactory
menambahkan amr
klaim ke klaim pengguna hanya setelah berhasil masuk. Nilai klaim dibaca dari database. Klaim ditambahkan di sini karena pengguna hanya boleh mengakses tampilan yang dilindungi yang identity lebih tinggi jika telah masuk dengan MFA. Jika tampilan database dibaca dari database secara langsung alih-alih menggunakan klaim, dimungkinkan untuk mengakses tampilan tanpa MFA langsung setelah mengaktifkan MFA.
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;
}
}
}
Identity Karena pengaturan layanan berubah di Startup
kelas, tata letak Identity perlu diperbarui. Perancah Identity halaman ke dalam aplikasi. Tentukan tata letak dalam Identity/Account/Manage/_Layout.cshtml
file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Tetapkan juga tata letak untuk semua halaman kelola dari Identity halaman:
@{
Layout = "_Layout.cshtml";
}
Memvalidasi persyaratan MFA di halaman administrasi
Halaman administrasi Razor memvalidasi bahwa pengguna telah masuk menggunakan MFA. Dalam metode ini OnGet
, identity digunakan untuk mengakses klaim pengguna. Klaim amr
diperiksa untuk nilai mfa
. identity Jika klaim ini hilang atau , false
halaman akan dialihkan ke halaman Aktifkan MFA. Ini dimungkinkan karena pengguna telah masuk, tetapi tanpa 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();
}
}
}
Logika UI untuk mengalihkan informasi masuk pengguna
Kebijakan otorisasi ditambahkan saat startup. Kebijakan memerlukan amr
klaim dengan nilai mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Kebijakan ini kemudian dapat digunakan dalam _Layout
tampilan untuk menampilkan atau menyembunyikan menu Admin dengan peringatan:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
identity Jika telah masuk menggunakan MFA, menu Admin ditampilkan tanpa peringatan tipsalat. Ketika pengguna telah masuk tanpa MFA, menu Admin (Tidak Diaktifkan) ditampilkan bersama dengan tipsalat yang memberi tahu pengguna (menjelaskan peringatan).
@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>
}
}
Jika pengguna masuk tanpa MFA, peringatan akan ditampilkan:
Pengguna dialihkan ke tampilan aktifkan MFA saat mengklik tautan Admin :
Mengirim persyaratan masuk MFA ke server OpenID Connect
Parameter acr_values
dapat digunakan untuk meneruskan nilai yang mfa
diperlukan dari klien ke server dalam permintaan autentikasi.
Catatan
Parameter acr_values
perlu ditangani pada server OpenID Connect agar ini berfungsi.
Klien OpenID Connect ASP.NET Core
Aplikasi klien OpenID Connect Halaman Inti Razor ASP.NET menggunakan AddOpenIdConnect
metode untuk masuk ke server OpenID Connect. Parameter acr_values
diatur dengan mfa
nilai dan dikirim dengan permintaan autentikasi. OpenIdConnectEvents
digunakan untuk menambahkan ini.
Untuk nilai parameter yang direkomendasikan acr_values
, lihat Nilai Referensi Metode Autentikasi.
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");
});
Contoh server OpenID Connect Duende IdentityServer dengan ASP.NET Core Identity
Pada server OpenID Connect, yang diimplementasikan menggunakan ASP.NET Core Identity dengan Razor Pages, halaman baru bernama ErrorEnable2FA.cshtml
dibuat. Tampilan:
- Menampilkan jika Identity berasal dari aplikasi yang memerlukan MFA tetapi pengguna belum mengaktifkan ini di Identity.
- Memberi tahu pengguna dan menambahkan tautan untuk mengaktifkan ini.
@{
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>
Dalam metode ini Login
, IIdentityServerInteractionService
implementasi _interaction
antarmuka digunakan untuk mengakses parameter permintaan OpenID Connect. Parameter acr_values
diakses menggunakan AcrValues
properti . Saat klien mengirim ini dengan mfa
set, ini kemudian dapat diperiksa.
Jika MFA diperlukan, dan pengguna di ASP.NET Core Identity mengaktifkan MFA, maka login berlanjut. Ketika pengguna tidak mengaktifkan MFA, pengguna dialihkan ke tampilan ErrorEnable2FA.cshtml
kustom . Kemudian ASP.NET Core Identity memasukkan pengguna.
Fido2Store digunakan untuk memeriksa apakah pengguna telah mengaktifkan MFA menggunakan Penyedia Token FIDO2 kustom.
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();
}
Jika pengguna sudah masuk, aplikasi klien:
- Masih memvalidasi
amr
klaim. - Dapat menyiapkan MFA dengan tautan ke tampilan ASP.NET Core Identity .
Paksa ASP.NET klien Core OpenID Connect untuk mewajibkan MFA
Contoh ini menunjukkan bagaimana aplikasi ASP.NET Core Razor Page, yang menggunakan OpenID Connect untuk masuk, dapat mengharuskan pengguna telah mengautentikasi menggunakan MFA.
Untuk memvalidasi persyaratan MFA, IAuthorizationRequirement
persyaratan dibuat. Ini akan ditambahkan ke halaman menggunakan kebijakan yang memerlukan MFA.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Diimplementasikan AuthorizationHandler
yang akan menggunakan amr
klaim dan memeriksa nilai mfa
. amr
dikembalikan dalam id_token
autentikasi yang berhasil dan dapat memiliki banyak nilai yang berbeda seperti yang didefinisikan dalam spesifikasi Nilai Referensi Metode Autentikasi.
Nilai yang dikembalikan tergantung pada bagaimana terautentikasi identity dan pada implementasi server OpenID Connect.
menggunakan AuthorizationHandler
RequireMfa
persyaratan dan memvalidasi amr
klaim. Server OpenID Connect dapat diimplementasikan menggunakan Duende Identity Server dengan ASP.NET Core Identity. Saat pengguna masuk menggunakan TOTP, amr
klaim dikembalikan dengan nilai MFA. Jika menggunakan implementasi server OpenID Connect yang berbeda atau jenis MFA yang berbeda, amr
klaim akan, atau dapat, memiliki nilai yang berbeda. Kode harus diperluas untuk menerima ini juga.
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;
}
}
Dalam file program, AddOpenIdConnect
metode digunakan sebagai skema tantangan default. Handler otorisasi, yang digunakan untuk memeriksa amr
klaim, ditambahkan ke kontainer Inversion of Control. Kebijakan kemudian dibuat yang menambahkan RequireMfa
persyaratan.
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();
Kebijakan ini kemudian digunakan di Razor halaman sesuai kebutuhan. Kebijakan ini juga dapat ditambahkan secara global untuk seluruh aplikasi.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Jika pengguna mengautentikasi tanpa MFA, amr
klaim mungkin akan memiliki pwd
nilai. Permintaan tidak akan diotorisasi untuk mengakses halaman. Dengan menggunakan nilai default, pengguna akan diarahkan ke halaman Akun/AccessDenied . Perilaku ini dapat diubah atau Anda dapat menerapkan logika kustom Anda sendiri di sini. Dalam contoh ini, tautan ditambahkan sehingga pengguna yang valid dapat menyiapkan MFA untuk akun mereka.
@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>
Sekarang hanya pengguna yang mengautentikasi dengan MFA yang dapat mengakses halaman atau situs web. Jika jenis MFA yang berbeda digunakan atau jika 2FA baik-baik saja, amr
klaim akan memiliki nilai yang berbeda dan perlu diproses dengan benar. Server OpenID Connect yang berbeda juga mengembalikan nilai yang berbeda untuk klaim ini dan mungkin tidak mengikuti spesifikasi Nilai Referensi Metode Autentikasi.
Saat masuk tanpa MFA (misalnya, hanya menggunakan kata sandi):
memiliki
amr
pwd
nilai:Akses ditolak:
Atau, masuk menggunakan OTP dengan Identity:
Kustomisasi Parameter OIDC dan OAuth
Opsi handler AdditionalAuthorizationParameters
autentikasi OAuth dan OIDC memungkinkan penyesuaian parameter pesan otorisasi yang biasanya disertakan sebagai bagian dari string kueri pengalihan:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Sumber Daya Tambahan:
Oleh Damien Bowden
Melihat atau mengunduh kode sampel (repositori GitHub damienbod/AspNetCoreHybridFlowWithApi)
Autentikasi multifaktor (MFA) adalah proses di mana pengguna diminta selama peristiwa masuk untuk bentuk identifikasi tambahan. Perintah ini bisa untuk memasukkan kode dari ponsel, menggunakan kunci FIDO2, atau untuk memberikan pemindaian sidik jari. Ketika Anda memerlukan bentuk autentikasi kedua, keamanan ditingkatkan. Faktor tambahan tidak mudah diperoleh atau diduplikasi oleh serangan cyber.
Artikel ini membahas area berikut:
- Apa itu MFA dan alur MFA apa yang direkomendasikan
- Mengonfigurasi MFA untuk halaman administrasi menggunakan ASP.NET Core Identity
- Mengirim persyaratan masuk MFA ke server OpenID Connect
- Paksa ASP.NET klien Core OpenID Connect untuk mewajibkan MFA
MFA, 2FA
MFA memerlukan setidaknya dua atau lebih jenis bukti untuk sesuatu seperti yang identity Anda ketahui, sesuatu yang Anda miliki, atau validasi biometrik bagi pengguna untuk diautentikasi.
Autentikasi dua faktor (2FA) seperti subset MFA, tetapi perbedaannya adalah bahwa MFA dapat memerlukan dua faktor atau lebih untuk membuktikan identity.
2FA didukung secara default saat menggunakan ASP.NET Core Identity. Untuk mengaktifkan atau menonaktifkan 2FA untuk pengguna tertentu, atur IdentityUser<TKey>.TwoFactorEnabled properti . UI Default ASP.NET Core Identity menyertakan halaman untuk mengonfigurasi 2FA.
MFA TOTP (Algoritma Kata Sandi Satu Kali Berbasis Waktu)
MFA yang menggunakan TOTP didukung secara default saat menggunakan ASP.NET Core Identity. Pendekatan ini dapat digunakan bersama dengan aplikasi pengautentikasi yang sesuai, termasuk:
- Microsoft Authenticator
- Google Authenticator
Untuk detail implementasi, lihat Mengaktifkan pembuatan Kode QR untuk aplikasi pengautentikasi TOTP di ASP.NET Core.
Untuk menonaktifkan dukungan untuk MFA TOTP, konfigurasikan autentikasi menggunakan AddIdentity alih-alih AddDefaultIdentity. AddDefaultIdentity
AddDefaultTokenProviders memanggil secara internal, yang mendaftarkan beberapa penyedia token termasuk satu untuk MFA TOTP. Untuk mendaftarkan hanya penyedia token tertentu, panggil AddTokenProvider untuk setiap penyedia yang diperlukan. Untuk informasi selengkapnya tentang penyedia token yang tersedia, lihat sumber AddDefaultTokenProviders di GitHub.
Kode akses MFA/FIDO2 atau tanpa kata sandi
passkeys/FIDO2 saat ini:
- Cara paling aman untuk mencapai MFA.
- MFA yang melindungi dari serangan phishing. (Serta autentikasi sertifikat dan Windows untuk bisnis)
Saat ini, ASP.NET Core tidak mendukung passkeys/FIDO2 secara langsung. Passkeys/FIDO2 dapat digunakan untuk alur MFA atau tanpa kata sandi.
MICROSOFT Entra ID menyediakan dukungan untuk passkeys/FIDO2 dan alur tanpa kata sandi. Untuk informasi selengkapnya, lihat Opsi autentikasi tanpa kata sandi.
Bentuk lain dari MFA tanpa kata sandi tidak atau mungkin tidak melindungi dari phishing.
MFA SMS
MFA dengan SMS meningkatkan keamanan secara besar-besaran dibandingkan dengan autentikasi kata sandi (faktor tunggal). Namun, menggunakan SMS sebagai faktor kedua tidak lagi direkomendasikan. Terlalu banyak vektor serangan yang diketahui ada untuk jenis implementasi ini.
Mengonfigurasi MFA untuk halaman administrasi menggunakan ASP.NET Core Identity
MFA dapat dipaksa pada pengguna untuk mengakses halaman sensitif dalam aplikasi ASP.NET Core Identity . Ini bisa berguna untuk aplikasi di mana berbagai tingkat akses ada untuk identitas yang berbeda. Misalnya, pengguna mungkin dapat melihat data profil menggunakan login kata sandi, tetapi administrator akan diminta untuk menggunakan MFA untuk mengakses halaman administratif.
Memperpanjang login dengan klaim MFA
Kode demo disiapkan menggunakan ASP.NET Core dengan Identity dan Razor Pages. Metode AddIdentity
ini digunakan alih-alih AddDefaultIdentity
satu, sehingga IUserClaimsPrincipalFactory
implementasi dapat digunakan untuk menambahkan klaim ke identity setelah login yang berhasil.
Peringatan
Artikel ini memperlihatkan penggunaan string koneksi. Dengan database lokal, pengguna tidak perlu diautentikasi, tetapi dalam produksi, string koneksi terkadang menyertakan kata sandi untuk mengautentikasi. Kredensial kata sandi pemilik sumber daya (ROPC) adalah risiko keamanan yang harus dihindari dalam database produksi. Aplikasi produksi harus menggunakan alur autentikasi paling aman yang tersedia. Untuk informasi selengkapnya tentang autentikasi untuk aplikasi yang disebarkan untuk menguji atau lingkungan produksi, lihat Mengamankan alur autentikasi.
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();
Kelas AdditionalUserClaimsPrincipalFactory
menambahkan amr
klaim ke klaim pengguna hanya setelah berhasil masuk. Nilai klaim dibaca dari database. Klaim ditambahkan di sini karena pengguna hanya boleh mengakses tampilan yang dilindungi yang identity lebih tinggi jika telah masuk dengan MFA. Jika tampilan database dibaca dari database secara langsung alih-alih menggunakan klaim, dimungkinkan untuk mengakses tampilan tanpa MFA langsung setelah mengaktifkan MFA.
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;
}
}
}
Identity Karena pengaturan layanan berubah di Startup
kelas, tata letak Identity perlu diperbarui. Perancah Identity halaman ke dalam aplikasi. Tentukan tata letak dalam Identity/Account/Manage/_Layout.cshtml
file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Tetapkan juga tata letak untuk semua halaman kelola dari Identity halaman:
@{
Layout = "_Layout.cshtml";
}
Memvalidasi persyaratan MFA di halaman administrasi
Halaman administrasi Razor memvalidasi bahwa pengguna telah masuk menggunakan MFA. Dalam metode ini OnGet
, identity digunakan untuk mengakses klaim pengguna. Klaim amr
diperiksa untuk nilai mfa
. identity Jika klaim ini hilang atau , false
halaman akan dialihkan ke halaman Aktifkan MFA. Ini dimungkinkan karena pengguna telah masuk, tetapi tanpa 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();
}
}
}
Logika UI untuk mengalihkan informasi masuk pengguna
Kebijakan otorisasi ditambahkan saat startup. Kebijakan memerlukan amr
klaim dengan nilai mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Kebijakan ini kemudian dapat digunakan dalam _Layout
tampilan untuk menampilkan atau menyembunyikan menu Admin dengan peringatan:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
identity Jika telah masuk menggunakan MFA, menu Admin ditampilkan tanpa peringatan tipsalat. Ketika pengguna telah masuk tanpa MFA, menu Admin (Tidak Diaktifkan) ditampilkan bersama dengan tipsalat yang memberi tahu pengguna (menjelaskan peringatan).
@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>
}
}
Jika pengguna masuk tanpa MFA, peringatan akan ditampilkan:
Pengguna dialihkan ke tampilan aktifkan MFA saat mengklik tautan Admin :
Mengirim persyaratan masuk MFA ke server OpenID Connect
Parameter acr_values
dapat digunakan untuk meneruskan nilai yang mfa
diperlukan dari klien ke server dalam permintaan autentikasi.
Catatan
Parameter acr_values
perlu ditangani pada server OpenID Connect agar ini berfungsi.
Klien OpenID Connect ASP.NET Core
Aplikasi klien OpenID Connect Halaman Inti Razor ASP.NET menggunakan AddOpenIdConnect
metode untuk masuk ke server OpenID Connect. Parameter acr_values
diatur dengan mfa
nilai dan dikirim dengan permintaan autentikasi. OpenIdConnectEvents
digunakan untuk menambahkan ini.
Untuk nilai parameter yang direkomendasikan acr_values
, lihat Nilai Referensi Metode Autentikasi.
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);
}
};
});
Contoh server OpenID Connect Duende IdentityServer dengan ASP.NET Core Identity
Pada server OpenID Connect, yang diimplementasikan menggunakan ASP.NET Core Identity dengan Razor Pages, halaman baru bernama ErrorEnable2FA.cshtml
dibuat. Tampilan:
- Menampilkan jika Identity berasal dari aplikasi yang memerlukan MFA tetapi pengguna belum mengaktifkan ini di Identity.
- Memberi tahu pengguna dan menambahkan tautan untuk mengaktifkan ini.
@{
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>
Dalam metode ini Login
, IIdentityServerInteractionService
implementasi _interaction
antarmuka digunakan untuk mengakses parameter permintaan OpenID Connect. Parameter acr_values
diakses menggunakan AcrValues
properti . Saat klien mengirim ini dengan mfa
set, ini kemudian dapat diperiksa.
Jika MFA diperlukan, dan pengguna di ASP.NET Core Identity mengaktifkan MFA, maka login berlanjut. Ketika pengguna tidak mengaktifkan MFA, pengguna dialihkan ke tampilan ErrorEnable2FA.cshtml
kustom . Kemudian ASP.NET Core Identity memasukkan pengguna.
Fido2Store digunakan untuk memeriksa apakah pengguna telah mengaktifkan MFA menggunakan Penyedia Token FIDO2 kustom.
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();
}
Jika pengguna sudah masuk, aplikasi klien:
- Masih memvalidasi
amr
klaim. - Dapat menyiapkan MFA dengan tautan ke tampilan ASP.NET Core Identity .
Paksa ASP.NET klien Core OpenID Connect untuk mewajibkan MFA
Contoh ini menunjukkan bagaimana aplikasi ASP.NET Core Razor Page, yang menggunakan OpenID Connect untuk masuk, dapat mengharuskan pengguna telah mengautentikasi menggunakan MFA.
Untuk memvalidasi persyaratan MFA, IAuthorizationRequirement
persyaratan dibuat. Ini akan ditambahkan ke halaman menggunakan kebijakan yang memerlukan MFA.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Diimplementasikan AuthorizationHandler
yang akan menggunakan amr
klaim dan memeriksa nilai mfa
. amr
dikembalikan dalam id_token
autentikasi yang berhasil dan dapat memiliki banyak nilai yang berbeda seperti yang didefinisikan dalam spesifikasi Nilai Referensi Metode Autentikasi.
Nilai yang dikembalikan tergantung pada bagaimana terautentikasi identity dan pada implementasi server OpenID Connect.
menggunakan AuthorizationHandler
RequireMfa
persyaratan dan memvalidasi amr
klaim. Server OpenID Connect dapat diimplementasikan menggunakan Duende Identity Server dengan ASP.NET Core Identity. Saat pengguna masuk menggunakan TOTP, amr
klaim dikembalikan dengan nilai MFA. Jika menggunakan implementasi server OpenID Connect yang berbeda atau jenis MFA yang berbeda, amr
klaim akan, atau dapat, memiliki nilai yang berbeda. Kode harus diperluas untuk menerima ini juga.
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;
}
}
Dalam file program, AddOpenIdConnect
metode digunakan sebagai skema tantangan default. Handler otorisasi, yang digunakan untuk memeriksa amr
klaim, ditambahkan ke kontainer Inversion of Control. Kebijakan kemudian dibuat yang menambahkan RequireMfa
persyaratan.
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();
Kebijakan ini kemudian digunakan di Razor halaman sesuai kebutuhan. Kebijakan ini juga dapat ditambahkan secara global untuk seluruh aplikasi.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Jika pengguna mengautentikasi tanpa MFA, amr
klaim mungkin akan memiliki pwd
nilai. Permintaan tidak akan diotorisasi untuk mengakses halaman. Dengan menggunakan nilai default, pengguna akan diarahkan ke halaman Akun/AccessDenied . Perilaku ini dapat diubah atau Anda dapat menerapkan logika kustom Anda sendiri di sini. Dalam contoh ini, tautan ditambahkan sehingga pengguna yang valid dapat menyiapkan MFA untuk akun mereka.
@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>
Sekarang hanya pengguna yang mengautentikasi dengan MFA yang dapat mengakses halaman atau situs web. Jika jenis MFA yang berbeda digunakan atau jika 2FA baik-baik saja, amr
klaim akan memiliki nilai yang berbeda dan perlu diproses dengan benar. Server OpenID Connect yang berbeda juga mengembalikan nilai yang berbeda untuk klaim ini dan mungkin tidak mengikuti spesifikasi Nilai Referensi Metode Autentikasi.
Saat masuk tanpa MFA (misalnya, hanya menggunakan kata sandi):
memiliki
amr
pwd
nilai:Akses ditolak:
Atau, masuk menggunakan OTP dengan Identity:
Sumber Daya Tambahan:
Oleh Damien Bowden
Melihat atau mengunduh kode sampel (repositori GitHub damienbod/AspNetCoreHybridFlowWithApi)
Autentikasi multifaktor (MFA) adalah proses di mana pengguna diminta selama peristiwa masuk untuk bentuk identifikasi tambahan. Perintah ini bisa untuk memasukkan kode dari ponsel, menggunakan kunci FIDO2, atau untuk memberikan pemindaian sidik jari. Ketika Anda memerlukan bentuk autentikasi kedua, keamanan ditingkatkan. Faktor tambahan tidak mudah diperoleh atau diduplikasi oleh serangan cyber.
Artikel ini membahas area berikut:
- Apa itu MFA dan alur MFA apa yang direkomendasikan
- Mengonfigurasi MFA untuk halaman administrasi menggunakan ASP.NET Core Identity
- Mengirim persyaratan masuk MFA ke server OpenID Connect
- Paksa ASP.NET klien Core OpenID Connect untuk mewajibkan MFA
MFA, 2FA
MFA memerlukan setidaknya dua atau lebih jenis bukti untuk sesuatu seperti yang identity Anda ketahui, sesuatu yang Anda miliki, atau validasi biometrik bagi pengguna untuk diautentikasi.
Autentikasi dua faktor (2FA) seperti subset MFA, tetapi perbedaannya adalah bahwa MFA dapat memerlukan dua faktor atau lebih untuk membuktikan identity.
MFA TOTP (Algoritma Kata Sandi Satu Kali Berbasis Waktu)
MFA menggunakan TOTP adalah implementasi yang didukung menggunakan ASP.NET Core Identity. Ini dapat digunakan bersama dengan aplikasi pengautentikasi yang sesuai, termasuk:
- Aplikasi Microsoft Authenticator
- Aplikasi Google Authenticator
Lihat tautan berikut untuk detail implementasi:
Mengaktifkan pembuatan Kode QR untuk aplikasi pengautentikasi TOTP di ASP.NET Core
Kode akses MFA/FIDO2 atau tanpa kata sandi
passkeys/FIDO2 saat ini:
- Cara paling aman untuk mencapai MFA.
- MFA yang melindungi dari serangan phishing. (Serta autentikasi sertifikat dan Windows untuk bisnis)
Saat ini, ASP.NET Core tidak mendukung passkeys/FIDO2 secara langsung. Passkeys/FIDO2 dapat digunakan untuk alur MFA atau tanpa kata sandi.
MICROSOFT Entra ID menyediakan dukungan untuk passkeys/FIDO2 dan alur tanpa kata sandi. Untuk informasi selengkapnya, lihat Opsi autentikasi tanpa kata sandi.
Bentuk lain dari MFA tanpa kata sandi tidak atau mungkin tidak melindungi dari phishing.
MFA SMS
MFA dengan SMS meningkatkan keamanan secara besar-besaran dibandingkan dengan autentikasi kata sandi (faktor tunggal). Namun, menggunakan SMS sebagai faktor kedua tidak lagi direkomendasikan. Terlalu banyak vektor serangan yang diketahui ada untuk jenis implementasi ini.
Mengonfigurasi MFA untuk halaman administrasi menggunakan ASP.NET Core Identity
MFA dapat dipaksa pada pengguna untuk mengakses halaman sensitif dalam aplikasi ASP.NET Core Identity . Ini bisa berguna untuk aplikasi di mana berbagai tingkat akses ada untuk identitas yang berbeda. Misalnya, pengguna mungkin dapat melihat data profil menggunakan login kata sandi, tetapi administrator akan diminta untuk menggunakan MFA untuk mengakses halaman administratif.
Memperpanjang login dengan klaim MFA
Kode demo disiapkan menggunakan ASP.NET Core dengan Identity dan Razor Pages. Metode AddIdentity
ini digunakan alih-alih AddDefaultIdentity
satu, sehingga IUserClaimsPrincipalFactory
implementasi dapat digunakan untuk menambahkan klaim ke identity setelah login yang berhasil.
Peringatan
Artikel ini memperlihatkan penggunaan string koneksi. Dengan database lokal, pengguna tidak perlu diautentikasi, tetapi dalam produksi, string koneksi terkadang menyertakan kata sandi untuk mengautentikasi. Kredensial kata sandi pemilik sumber daya (ROPC) adalah risiko keamanan yang harus dihindari dalam database produksi. Aplikasi produksi harus menggunakan alur autentikasi paling aman yang tersedia. Untuk informasi selengkapnya tentang autentikasi untuk aplikasi yang disebarkan untuk menguji atau lingkungan produksi, lihat Mengamankan alur autentikasi.
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();
}
Kelas AdditionalUserClaimsPrincipalFactory
menambahkan amr
klaim ke klaim pengguna hanya setelah berhasil masuk. Nilai klaim dibaca dari database. Klaim ditambahkan di sini karena pengguna hanya boleh mengakses tampilan yang dilindungi yang identity lebih tinggi jika telah masuk dengan MFA. Jika tampilan database dibaca dari database secara langsung alih-alih menggunakan klaim, dimungkinkan untuk mengakses tampilan tanpa MFA langsung setelah mengaktifkan MFA.
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;
}
}
}
Identity Karena pengaturan layanan berubah di Startup
kelas, tata letak Identity perlu diperbarui. Perancah Identity halaman ke dalam aplikasi. Tentukan tata letak dalam Identity/Account/Manage/_Layout.cshtml
file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Tetapkan juga tata letak untuk semua halaman kelola dari Identity halaman:
@{
Layout = "_Layout.cshtml";
}
Memvalidasi persyaratan MFA di halaman administrasi
Halaman administrasi Razor memvalidasi bahwa pengguna telah masuk menggunakan MFA. Dalam metode ini OnGet
, identity digunakan untuk mengakses klaim pengguna. Klaim amr
diperiksa untuk nilai mfa
. identity Jika klaim ini hilang atau , false
halaman akan dialihkan ke halaman Aktifkan MFA. Ini dimungkinkan karena pengguna telah masuk, tetapi tanpa 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();
}
}
}
Logika UI untuk mengalihkan informasi masuk pengguna
Kebijakan otorisasi ditambahkan dalam file program. Kebijakan memerlukan amr
klaim dengan nilai mfa
.
builder.Services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Kebijakan ini kemudian dapat digunakan dalam _Layout
tampilan untuk menampilkan atau menyembunyikan menu Admin dengan peringatan:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
identity Jika telah masuk menggunakan MFA, menu Admin ditampilkan tanpa peringatan tipsalat. Ketika pengguna telah masuk tanpa MFA, menu Admin (Tidak Diaktifkan) ditampilkan bersama dengan tipsalat yang memberi tahu pengguna (menjelaskan peringatan).
@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>
}
}
Jika pengguna masuk tanpa MFA, peringatan akan ditampilkan:
Pengguna dialihkan ke tampilan aktifkan MFA saat mengklik tautan Admin :
Mengirim persyaratan masuk MFA ke server OpenID Connect
Parameter acr_values
dapat digunakan untuk meneruskan nilai yang mfa
diperlukan dari klien ke server dalam permintaan autentikasi.
Catatan
Parameter acr_values
perlu ditangani pada server OpenID Connect agar ini berfungsi.
Klien OpenID Connect ASP.NET Core
Aplikasi klien OpenID Connect Halaman Inti Razor ASP.NET menggunakan AddOpenIdConnect
metode untuk masuk ke server OpenID Connect. Parameter acr_values
diatur dengan mfa
nilai dan dikirim dengan permintaan autentikasi. OpenIdConnectEvents
digunakan untuk menambahkan ini.
Untuk nilai parameter yang direkomendasikan acr_values
, lihat Nilai Referensi Metode Autentikasi.
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);
}
};
});
Contoh server OpenID Connect IdentityServer 4 dengan ASP.NET Core Identity
Pada server OpenID Connect, yang diimplementasikan menggunakan ASP.NET Core Identity dengan tampilan MVC, tampilan baru bernama ErrorEnable2FA.cshtml
dibuat. Tampilan:
- Menampilkan jika Identity berasal dari aplikasi yang memerlukan MFA tetapi pengguna belum mengaktifkan ini di Identity.
- Memberi tahu pengguna dan menambahkan tautan untuk mengaktifkan ini.
@{
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>
Dalam metode ini Login
, IIdentityServerInteractionService
implementasi _interaction
antarmuka digunakan untuk mengakses parameter permintaan OpenID Connect. Parameter acr_values
diakses menggunakan AcrValues
properti . Saat klien mengirim ini dengan mfa
set, ini kemudian dapat diperiksa.
Jika MFA diperlukan, dan pengguna di ASP.NET Core Identity mengaktifkan MFA, maka login berlanjut. Ketika pengguna tidak mengaktifkan MFA, pengguna dialihkan ke tampilan ErrorEnable2FA.cshtml
kustom . Kemudian ASP.NET Core Identity memasukkan pengguna.
//
// 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
Metode ini ExternalLoginCallback
berfungsi seperti login lokal Identity . Properti AcrValues
diperiksa untuk nilainya mfa
. mfa
Jika nilai ada, MFA dipaksa sebelum login selesai (misalnya, dialihkan ke ErrorEnable2FA
tampilan).
//
// 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
Jika pengguna sudah masuk, aplikasi klien:
- Masih memvalidasi
amr
klaim. - Dapat menyiapkan MFA dengan tautan ke tampilan ASP.NET Core Identity .
Paksa ASP.NET klien Core OpenID Connect untuk mewajibkan MFA
Contoh ini menunjukkan bagaimana aplikasi ASP.NET Core Razor Page, yang menggunakan OpenID Connect untuk masuk, dapat mengharuskan pengguna telah mengautentikasi menggunakan MFA.
Untuk memvalidasi persyaratan MFA, IAuthorizationRequirement
persyaratan dibuat. Ini akan ditambahkan ke halaman menggunakan kebijakan yang memerlukan MFA.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc
{
public class RequireMfa : IAuthorizationRequirement{}
}
Diimplementasikan AuthorizationHandler
yang akan menggunakan amr
klaim dan memeriksa nilai mfa
. amr
dikembalikan dalam id_token
autentikasi yang berhasil dan dapat memiliki banyak nilai yang berbeda seperti yang didefinisikan dalam spesifikasi Nilai Referensi Metode Autentikasi.
Nilai yang dikembalikan tergantung pada bagaimana terautentikasi identity dan pada implementasi server OpenID Connect.
menggunakan AuthorizationHandler
RequireMfa
persyaratan dan memvalidasi amr
klaim. Server OpenID Connect dapat diimplementasikan menggunakan IdentityServer4 dengan ASP.NET Core Identity. Saat pengguna masuk menggunakan TOTP, amr
klaim dikembalikan dengan nilai MFA. Jika menggunakan implementasi server OpenID Connect yang berbeda atau jenis MFA yang berbeda, amr
klaim akan, atau dapat, memiliki nilai yang berbeda. Kode harus diperluas untuk menerima ini juga.
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;
}
}
Dalam metode , Startup.ConfigureServices
AddOpenIdConnect
metode ini digunakan sebagai skema tantangan default. Handler otorisasi, yang digunakan untuk memeriksa amr
klaim, ditambahkan ke kontainer Inversion of Control. Kebijakan kemudian dibuat yang menambahkan RequireMfa
persyaratan.
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();
}
Kebijakan ini kemudian digunakan di Razor halaman sesuai kebutuhan. Kebijakan ini juga dapat ditambahkan secara global untuk seluruh aplikasi.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Jika pengguna mengautentikasi tanpa MFA, amr
klaim mungkin akan memiliki pwd
nilai. Permintaan tidak akan diotorisasi untuk mengakses halaman. Dengan menggunakan nilai default, pengguna akan diarahkan ke halaman Akun/AccessDenied . Perilaku ini dapat diubah atau Anda dapat menerapkan logika kustom Anda sendiri di sini. Dalam contoh ini, tautan ditambahkan sehingga pengguna yang valid dapat menyiapkan MFA untuk akun mereka.
@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>
Sekarang hanya pengguna yang mengautentikasi dengan MFA yang dapat mengakses halaman atau situs web. Jika jenis MFA yang berbeda digunakan atau jika 2FA baik-baik saja, amr
klaim akan memiliki nilai yang berbeda dan perlu diproses dengan benar. Server OpenID Connect yang berbeda juga mengembalikan nilai yang berbeda untuk klaim ini dan mungkin tidak mengikuti spesifikasi Nilai Referensi Metode Autentikasi.
Saat masuk tanpa MFA (misalnya, hanya menggunakan kata sandi):
memiliki
amr
pwd
nilai:Akses ditolak:
Atau, masuk menggunakan OTP dengan Identity:
Sumber Daya Tambahan:
ASP.NET Core