Многофакторная проверка подлинности в ASP.NET Core
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в статье о политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 8 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 8 этой статьи.
Просмотр или скачивание примера кода (репозиторий damienbod/AspNetCoreHybridFlowWithApi GitHub)
Многофакторная проверка подлинности (MFA) — это процесс, в котором пользователь запрашивается во время события входа для дополнительных форм идентификации. Это может быть ввод кода с мобильного телефона, использование ключа FIDO2 или проверка отпечатков пальцев. Если требуется вторая форма проверки подлинности, безопасность улучшается. Дополнительный фактор не легко получается или дублируется кибератакой.
В этой статье рассматриваются следующие области:
- Что такое MFA и какие потоки MFA рекомендуется
- Настройка MFA для страниц администрирования с помощью ASP.NET Core Identity
- Отправка требования к входу MFA на сервер OpenID Connect
- Принудительное использование клиента OpenID Connect для ASP.NET Core, требуемого многофакторной проверки подлинности
MFA, 2FA
Для проверки подлинности MFA требуется по крайней мере два или более типов подтверждения identity , например то, что вы знаете, что вы обладаете, или биометрические проверки для пользователя.
Двухфакторная проверка подлинности (2FA) похожа на подмножество MFA, но разница в том, что MFA может требовать два или более факторов для подтверждения identity.
2FA поддерживается по умолчанию при использовании ASP.NET Core Identity. Чтобы включить или отключить 2FA для определенного пользователя, задайте IdentityUser<TKey>.TwoFactorEnabled свойство. Пользовательский интерфейс по умолчанию ASP.NET Core Identity включает страницы для настройки 2FA.
MFA TOTP (алгоритм одноразового пароля на основе времени)
MFA с помощью TOTP поддерживается по умолчанию при использовании ASP.NET Core Identity. Этот подход можно использовать вместе с любым приложением для проверки подлинности, в том числе:
- Microsoft Authenticator
- Google Authenticator
Сведения о реализации см. в разделе "Включение создания QR-кода" для приложений проверки подлинности TOTP в ASP.NET Core.
Чтобы отключить поддержку MFA TOTP, настройте проверку подлинности, используя AddIdentity вместо AddDefaultIdentityнее. AddDefaultIdentity
вызывает внутренние вызовы AddDefaultTokenProviders , которые регистрируют несколько поставщиков маркеров, включая один для MFA TOTP. Чтобы зарегистрировать только конкретных поставщиков маркеров, вызовите AddTokenProvider для каждого обязательного поставщика. Дополнительные сведения о доступных поставщиках маркеров см. в источнике AddDefaultTokenProviders на GitHub.
Ключи доступа MFA/ FIDO2 или без пароля
passkeys/FIDO2 в настоящее время:
- Самый безопасный способ достижения MFA.
- Многофакторная проверка подлинности, которая защищает от фишинговых атак. (А также проверка подлинности на основе сертификатов и Windows для бизнеса)
В настоящее время ASP.NET Core не поддерживает ключи доступа или FIDO2 напрямую. Ключи доступа/FIDO2 можно использовать для потоков MFA или без пароля.
Идентификатор Microsoft Entra предоставляет поддержку потоков passkeys/FIDO2 и без пароля. Дополнительные сведения см. в разделе "Параметры проверки подлинности без пароля".
Другие формы без пароля MFA не защищаются от фишинга.
MFA SMS
Многофакторная проверка подлинности с помощью SMS значительно увеличивает безопасность по сравнению с проверкой подлинности паролем (один фактор). Однако использование SMS в качестве второго фактора больше не рекомендуется. Для этого типа реализации существует слишком много известных векторов атак.
Настройка MFA для страниц администрирования с помощью ASP.NET Core Identity
MFA может быть вынуждена пользователям получать доступ к конфиденциальным страницам в приложении ASP.NET Core Identity . Это может быть полезно для приложений, где существуют различные уровни доступа для различных удостоверений. Например, пользователи могут просматривать данные профиля с помощью имени входа в систему паролей, но администратору потребуется использовать MFA для доступа к административным страницам.
Расширение имени входа с помощью утверждения MFA
Демонстрационный код настраивается с помощью ASP.NET Core и Identity Razor Pages. Метод AddIdentity
используется вместо AddDefaultIdentity
одного, поэтому IUserClaimsPrincipalFactory
реализацию можно использовать для добавления утверждений в identity после успешного входа.
Предупреждение
В этой статье показано использование строка подключения. С локальной базой данных пользователь не должен пройти проверку подлинности, но в рабочей среде строка подключения иногда включают пароль для проверки подлинности. Учетные данные владельца ресурса (ROPC) — это риск безопасности, который следует избежать в рабочих базах данных. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для приложений, развернутых в тестовых или рабочих средах, см. в разделе "Безопасные потоки проверки подлинности".
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();
Класс AdditionalUserClaimsPrincipalFactory
добавляет amr
утверждение к утверждениям пользователя только после успешного входа. Значение утверждения считывается из базы данных. Утверждение добавляется здесь, так как пользователь должен получить доступ только к более защищенному представлению, если identity он вошел в систему с помощью MFA. Если представление базы данных считывается из базы данных непосредственно вместо использования утверждения, то можно получить доступ к представлению без MFA непосредственно после активации 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 Так как настройка службы изменилась в Startup
классе, макеты Identity необходимо обновить. Создание шаблонов Identity страниц в приложение. Определите макет в Identity/Account/Manage/_Layout.cshtml
файле.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Кроме того, назначьте макет для всех страниц управления со Identity страниц:
@{
Layout = "_Layout.cshtml";
}
Проверка требования MFA на странице администрирования
Страница администрирования Razor проверяет, выполнил ли пользователь вход с помощью MFA. В методе OnGet
identity используется для доступа к утверждениям пользователя. Утверждение amr
проверяется для значения mfa
. identity Если это утверждение отсутствует или нетfalse
, страница перенаправляется на страницу "Включить MFA". Это возможно, так как пользователь уже вошел в систему, но без 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();
}
}
}
Логика пользовательского интерфейса для переключения сведений о входе пользователя
Политика авторизации была добавлена при запуске. Для политики требуется amr
утверждение со значением mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Затем эту политику можно использовать в _Layout
представлении для отображения или скрытия меню администрирования с предупреждением:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Если вход identity в систему с помощью MFA выполнен, меню администрирования отображается без предупреждения подсказки. Когда пользователь выполнил вход без MFA, отображается меню администратора (не включено) вместе с подсказкой, которая сообщает пользователю (объясняя предупреждение).
@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>
}
}
Если пользователь входит в систему без MFA, отображается предупреждение:
Пользователь перенаправляется в режим включения MFA при нажатии ссылки администратора :
Отправка требования к входу MFA на сервер OpenID Connect
Этот acr_values
параметр можно использовать для передачи mfa
требуемого значения от клиента серверу в запросе проверки подлинности.
Примечание.
Этот acr_values
параметр необходимо обрабатывать на сервере OpenID Connect для работы.
Клиент OpenID Connect ASP.NET Core
Клиентское приложение OpenID Connect для ASP.NET Core Razor Pages использует AddOpenIdConnect
метод для входа на сервер OpenID Connect. Параметр acr_values
задается со значением mfa
и отправляется с помощью запроса проверки подлинности. Этот OpenIdConnectEvents
параметр используется для добавления.
Рекомендуемые значения параметров см. в разделе "Справочные acr_values
значения метода проверки подлинности".
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");
});
Пример сервера Duende IdentityServer OpenID Connect с ASP.NET Core Identity
На сервере OpenID Connect, который реализуется с помощью ASP.NET Core Identity с Razor Pages, создается новая страница с именем ErrorEnable2FA.cshtml
. Представление :
- Отображается, если Identity из приложения требуется многофакторная проверка подлинности, но пользователь не активировал это в Identity.
- Сообщает пользователю и добавляет ссылку для активации.
@{
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>
В методе Login
IIdentityServerInteractionService
реализация _interaction
интерфейса используется для доступа к параметрам запроса OpenID Connect. Доступ acr_values
к параметру AcrValues
осуществляется с помощью свойства. После отправки этого клиента с mfa
набором это можно проверить.
Если требуется MFA, и пользователь в ASP.NET Core Identity включил MFA, то имя входа продолжается. Если у пользователя нет многофакторной проверки подлинности, пользователь перенаправляется в пользовательское представление ErrorEnable2FA.cshtml
. Затем ASP.NET Core Identity войдите в систему пользователя.
Fido2Store используется для проверки того, активировал ли пользователь MFA с помощью пользовательского поставщика токенов FIDO2.
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();
}
Если пользователь уже вошел в систему, клиентское приложение:
- По-прежнему
amr
проверяет утверждение. - Может настроить MFA со ссылкой на представление ASP.NET Core Identity .
Принудительное использование клиента OpenID Connect для ASP.NET Core, требуемого многофакторной проверки подлинности
В этом примере показано, как приложение ASP.NET Core Razor Page, использующее OpenID Connect для входа, может требовать, чтобы пользователи прошли проверку подлинности с помощью MFA.
Чтобы проверить требование MFA, IAuthorizationRequirement
создается требование. Это будет добавлено на страницы с помощью политики, требующей многофакторной проверки подлинности.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Реализуется AuthorizationHandler
, который будет использовать amr
утверждение и проверять значение mfa
. Возвращается amr
в id_token
успешной проверке подлинности и может иметь множество различных значений, как определено в спецификации ссылочных значений метода проверки подлинности.
Возвращаемое значение зависит от способа identity проверки подлинности и реализации сервера OpenID Connect.
RequireMfa
Использует AuthorizationHandler
требование и проверяет amr
утверждение. Сервер OpenID Connect можно реализовать с помощью сервера Duende Identity с ASP.NET Core Identity. Когда пользователь входит в систему с помощью TOTP, amr
утверждение возвращается со значением MFA. Если используется другая реализация сервера OpenID Connect или другой тип MFA, amr
утверждение будет или может иметь другое значение. Код должен быть расширен, чтобы принять это, а также.
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;
}
}
В файле AddOpenIdConnect
программы метод используется в качестве схемы вызовов по умолчанию. Обработчик авторизации, используемый для проверки amr
утверждения, добавляется в контейнер Inversion of Control. Затем создается политика, которая добавляет 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();
Затем эта политика используется на Razor странице по мере необходимости. Политику можно добавить глобально для всего приложения.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Если пользователь проходит проверку подлинности без MFA, утверждение, вероятно, amr
будет иметь pwd
значение. Запрос не будет авторизован для доступа к странице. Используя значения по умолчанию, пользователь будет перенаправлен на страницу Account/AccessDenied . Это поведение можно изменить или реализовать собственную пользовательскую логику здесь. В этом примере добавляется ссылка, чтобы допустимый пользователь смог настроить MFA для своей учетной записи.
@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>
Теперь только пользователи, прошедшие проверку подлинности с помощью MFA, могут получить доступ к странице или веб-сайту. Если используются разные типы MFA или если 2FA хорошо, amr
утверждение будет иметь разные значения и должны быть обработаны правильно. Разные серверы OpenID Connect также возвращают разные значения для этого утверждения и могут не соответствовать спецификации ссылочных значений метода проверки подлинности.
При входе без MFA (например, с помощью пароля):
pwd
Имеетamr
значение:Доступ запрещен:
Кроме того, войдите в систему с помощью OTP:Identity
Настройка OIDC и параметра OAuth
Параметр обработчиков AdditionalAuthorizationParameters
проверки подлинности OAuth и OIDC позволяет настраивать параметры сообщения авторизации, которые обычно включаются в строку запроса перенаправления:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Дополнительные ресурсы
Просмотр или скачивание примера кода (репозиторий damienbod/AspNetCoreHybridFlowWithApi GitHub)
Многофакторная проверка подлинности (MFA) — это процесс, в котором пользователь запрашивается во время события входа для дополнительных форм идентификации. Это может быть ввод кода с мобильного телефона, использование ключа FIDO2 или проверка отпечатков пальцев. Если требуется вторая форма проверки подлинности, безопасность улучшается. Дополнительный фактор не легко получается или дублируется кибератакой.
В этой статье рассматриваются следующие области:
- Что такое MFA и какие потоки MFA рекомендуется
- Настройка MFA для страниц администрирования с помощью ASP.NET Core Identity
- Отправка требования к входу MFA на сервер OpenID Connect
- Принудительное использование клиента OpenID Connect для ASP.NET Core, требуемого многофакторной проверки подлинности
MFA, 2FA
Для проверки подлинности MFA требуется по крайней мере два или более типов подтверждения identity , например то, что вы знаете, что вы обладаете, или биометрические проверки для пользователя.
Двухфакторная проверка подлинности (2FA) похожа на подмножество MFA, но разница в том, что MFA может требовать два или более факторов для подтверждения identity.
2FA поддерживается по умолчанию при использовании ASP.NET Core Identity. Чтобы включить или отключить 2FA для определенного пользователя, задайте IdentityUser<TKey>.TwoFactorEnabled свойство. Пользовательский интерфейс по умолчанию ASP.NET Core Identity включает страницы для настройки 2FA.
MFA TOTP (алгоритм одноразового пароля на основе времени)
MFA с помощью TOTP поддерживается по умолчанию при использовании ASP.NET Core Identity. Этот подход можно использовать вместе с любым приложением для проверки подлинности, в том числе:
- Microsoft Authenticator
- Google Authenticator
Сведения о реализации см. в разделе "Включение создания QR-кода" для приложений проверки подлинности TOTP в ASP.NET Core.
Чтобы отключить поддержку MFA TOTP, настройте проверку подлинности, используя AddIdentity вместо AddDefaultIdentityнее. AddDefaultIdentity
вызывает внутренние вызовы AddDefaultTokenProviders , которые регистрируют несколько поставщиков маркеров, включая один для MFA TOTP. Чтобы зарегистрировать только конкретных поставщиков маркеров, вызовите AddTokenProvider для каждого обязательного поставщика. Дополнительные сведения о доступных поставщиках маркеров см. в источнике AddDefaultTokenProviders на GitHub.
Ключи доступа MFA/ FIDO2 или без пароля
passkeys/FIDO2 в настоящее время:
- Самый безопасный способ достижения MFA.
- Многофакторная проверка подлинности, которая защищает от фишинговых атак. (А также проверка подлинности на основе сертификатов и Windows для бизнеса)
В настоящее время ASP.NET Core не поддерживает ключи доступа или FIDO2 напрямую. Ключи доступа/FIDO2 можно использовать для потоков MFA или без пароля.
Идентификатор Microsoft Entra предоставляет поддержку потоков passkeys/FIDO2 и без пароля. Дополнительные сведения см. в разделе "Параметры проверки подлинности без пароля".
Другие формы без пароля MFA не защищаются от фишинга.
MFA SMS
Многофакторная проверка подлинности с помощью SMS значительно увеличивает безопасность по сравнению с проверкой подлинности паролем (один фактор). Однако использование SMS в качестве второго фактора больше не рекомендуется. Для этого типа реализации существует слишком много известных векторов атак.
Настройка MFA для страниц администрирования с помощью ASP.NET Core Identity
MFA может быть вынуждена пользователям получать доступ к конфиденциальным страницам в приложении ASP.NET Core Identity . Это может быть полезно для приложений, где существуют различные уровни доступа для различных удостоверений. Например, пользователи могут просматривать данные профиля с помощью имени входа в систему паролей, но администратору потребуется использовать MFA для доступа к административным страницам.
Расширение имени входа с помощью утверждения MFA
Демонстрационный код настраивается с помощью ASP.NET Core и Identity Razor Pages. Метод AddIdentity
используется вместо AddDefaultIdentity
одного, поэтому IUserClaimsPrincipalFactory
реализацию можно использовать для добавления утверждений в identity после успешного входа.
Предупреждение
В этой статье показано использование строка подключения. С локальной базой данных пользователь не должен пройти проверку подлинности, но в рабочей среде строка подключения иногда включают пароль для проверки подлинности. Учетные данные владельца ресурса (ROPC) — это риск безопасности, который следует избежать в рабочих базах данных. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для приложений, развернутых в тестовых или рабочих средах, см. в разделе "Безопасные потоки проверки подлинности".
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();
Класс AdditionalUserClaimsPrincipalFactory
добавляет amr
утверждение к утверждениям пользователя только после успешного входа. Значение утверждения считывается из базы данных. Утверждение добавляется здесь, так как пользователь должен получить доступ только к более защищенному представлению, если identity он вошел в систему с помощью MFA. Если представление базы данных считывается из базы данных непосредственно вместо использования утверждения, то можно получить доступ к представлению без MFA непосредственно после активации 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 Так как настройка службы изменилась в Startup
классе, макеты Identity необходимо обновить. Создание шаблонов Identity страниц в приложение. Определите макет в Identity/Account/Manage/_Layout.cshtml
файле.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Кроме того, назначьте макет для всех страниц управления со Identity страниц:
@{
Layout = "_Layout.cshtml";
}
Проверка требования MFA на странице администрирования
Страница администрирования Razor проверяет, выполнил ли пользователь вход с помощью MFA. В методе OnGet
identity используется для доступа к утверждениям пользователя. Утверждение amr
проверяется для значения mfa
. identity Если это утверждение отсутствует или нетfalse
, страница перенаправляется на страницу "Включить MFA". Это возможно, так как пользователь уже вошел в систему, но без 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();
}
}
}
Логика пользовательского интерфейса для переключения сведений о входе пользователя
Политика авторизации была добавлена при запуске. Для политики требуется amr
утверждение со значением mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Затем эту политику можно использовать в _Layout
представлении для отображения или скрытия меню администрирования с предупреждением:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Если вход identity в систему с помощью MFA выполнен, меню администрирования отображается без предупреждения подсказки. Когда пользователь выполнил вход без MFA, отображается меню администратора (не включено) вместе с подсказкой, которая сообщает пользователю (объясняя предупреждение).
@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>
}
}
Если пользователь входит в систему без MFA, отображается предупреждение:
Пользователь перенаправляется в режим включения MFA при нажатии ссылки администратора :
Отправка требования к входу MFA на сервер OpenID Connect
Этот acr_values
параметр можно использовать для передачи mfa
требуемого значения от клиента серверу в запросе проверки подлинности.
Примечание.
Этот acr_values
параметр необходимо обрабатывать на сервере OpenID Connect для работы.
Клиент OpenID Connect ASP.NET Core
Клиентское приложение OpenID Connect для ASP.NET Core Razor Pages использует AddOpenIdConnect
метод для входа на сервер OpenID Connect. Параметр acr_values
задается со значением mfa
и отправляется с помощью запроса проверки подлинности. Этот OpenIdConnectEvents
параметр используется для добавления.
Рекомендуемые значения параметров см. в разделе "Справочные acr_values
значения метода проверки подлинности".
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);
}
};
});
Пример сервера Duende IdentityServer OpenID Connect с ASP.NET Core Identity
На сервере OpenID Connect, который реализуется с помощью ASP.NET Core Identity с Razor Pages, создается новая страница с именем ErrorEnable2FA.cshtml
. Представление :
- Отображается, если Identity из приложения требуется многофакторная проверка подлинности, но пользователь не активировал это в Identity.
- Сообщает пользователю и добавляет ссылку для активации.
@{
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>
В методе Login
IIdentityServerInteractionService
реализация _interaction
интерфейса используется для доступа к параметрам запроса OpenID Connect. Доступ acr_values
к параметру AcrValues
осуществляется с помощью свойства. После отправки этого клиента с mfa
набором это можно проверить.
Если требуется MFA, и пользователь в ASP.NET Core Identity включил MFA, то имя входа продолжается. Если у пользователя нет многофакторной проверки подлинности, пользователь перенаправляется в пользовательское представление ErrorEnable2FA.cshtml
. Затем ASP.NET Core Identity войдите в систему пользователя.
Fido2Store используется для проверки того, активировал ли пользователь MFA с помощью пользовательского поставщика токенов FIDO2.
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();
}
Если пользователь уже вошел в систему, клиентское приложение:
- По-прежнему
amr
проверяет утверждение. - Может настроить MFA со ссылкой на представление ASP.NET Core Identity .
Принудительное использование клиента OpenID Connect для ASP.NET Core, требуемого многофакторной проверки подлинности
В этом примере показано, как приложение ASP.NET Core Razor Page, использующее OpenID Connect для входа, может требовать, чтобы пользователи прошли проверку подлинности с помощью MFA.
Чтобы проверить требование MFA, IAuthorizationRequirement
создается требование. Это будет добавлено на страницы с помощью политики, требующей многофакторной проверки подлинности.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Реализуется AuthorizationHandler
, который будет использовать amr
утверждение и проверять значение mfa
. Возвращается amr
в id_token
успешной проверке подлинности и может иметь множество различных значений, как определено в спецификации ссылочных значений метода проверки подлинности.
Возвращаемое значение зависит от способа identity проверки подлинности и реализации сервера OpenID Connect.
RequireMfa
Использует AuthorizationHandler
требование и проверяет amr
утверждение. Сервер OpenID Connect можно реализовать с помощью сервера Duende Identity с ASP.NET Core Identity. Когда пользователь входит в систему с помощью TOTP, amr
утверждение возвращается со значением MFA. Если используется другая реализация сервера OpenID Connect или другой тип MFA, amr
утверждение будет или может иметь другое значение. Код должен быть расширен, чтобы принять это, а также.
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;
}
}
В файле AddOpenIdConnect
программы метод используется в качестве схемы вызовов по умолчанию. Обработчик авторизации, используемый для проверки amr
утверждения, добавляется в контейнер Inversion of Control. Затем создается политика, которая добавляет 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();
Затем эта политика используется на Razor странице по мере необходимости. Политику можно добавить глобально для всего приложения.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Если пользователь проходит проверку подлинности без MFA, утверждение, вероятно, amr
будет иметь pwd
значение. Запрос не будет авторизован для доступа к странице. Используя значения по умолчанию, пользователь будет перенаправлен на страницу Account/AccessDenied . Это поведение можно изменить или реализовать собственную пользовательскую логику здесь. В этом примере добавляется ссылка, чтобы допустимый пользователь смог настроить MFA для своей учетной записи.
@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>
Теперь только пользователи, прошедшие проверку подлинности с помощью MFA, могут получить доступ к странице или веб-сайту. Если используются разные типы MFA или если 2FA хорошо, amr
утверждение будет иметь разные значения и должны быть обработаны правильно. Разные серверы OpenID Connect также возвращают разные значения для этого утверждения и могут не соответствовать спецификации ссылочных значений метода проверки подлинности.
При входе без MFA (например, с помощью пароля):
pwd
Имеетamr
значение:Доступ запрещен:
Кроме того, войдите в систему с помощью OTP:Identity
Дополнительные ресурсы
Просмотр или скачивание примера кода (репозиторий damienbod/AspNetCoreHybridFlowWithApi GitHub)
Многофакторная проверка подлинности (MFA) — это процесс, в котором пользователь запрашивается во время события входа для дополнительных форм идентификации. Это может быть ввод кода с мобильного телефона, использование ключа FIDO2 или проверка отпечатков пальцев. Если требуется вторая форма проверки подлинности, безопасность улучшается. Дополнительный фактор не легко получается или дублируется кибератакой.
В этой статье рассматриваются следующие области:
- Что такое MFA и какие потоки MFA рекомендуется
- Настройка MFA для страниц администрирования с помощью ASP.NET Core Identity
- Отправка требования к входу MFA на сервер OpenID Connect
- Принудительное использование клиента OpenID Connect для ASP.NET Core, требуемого многофакторной проверки подлинности
MFA, 2FA
Для проверки подлинности MFA требуется по крайней мере два или более типов подтверждения identity , например то, что вы знаете, что вы обладаете, или биометрические проверки для пользователя.
Двухфакторная проверка подлинности (2FA) похожа на подмножество MFA, но разница в том, что MFA может требовать два или более факторов для подтверждения identity.
MFA TOTP (алгоритм одноразового пароля на основе времени)
MFA с помощью TOTP — это поддерживаемая реализация с помощью ASP.NET Core Identity. Это можно использовать вместе с любым соответствующим приложением проверки подлинности, включая:
- Приложение Microsoft Authenticator
- Приложение Google Authenticator
Дополнительные сведения о реализации см. по следующей ссылке:
Включение создания QR-кодов для приложений проверки подлинности TOTP в ASP.NET Core
Ключи доступа MFA/ FIDO2 или без пароля
passkeys/FIDO2 в настоящее время:
- Самый безопасный способ достижения MFA.
- Многофакторная проверка подлинности, которая защищает от фишинговых атак. (А также проверка подлинности на основе сертификатов и Windows для бизнеса)
В настоящее время ASP.NET Core не поддерживает ключи доступа или FIDO2 напрямую. Ключи доступа/FIDO2 можно использовать для потоков MFA или без пароля.
Идентификатор Microsoft Entra предоставляет поддержку потоков passkeys/FIDO2 и без пароля. Дополнительные сведения см. в разделе "Параметры проверки подлинности без пароля".
Другие формы без пароля MFA не защищаются от фишинга.
MFA SMS
Многофакторная проверка подлинности с помощью SMS значительно увеличивает безопасность по сравнению с проверкой подлинности паролем (один фактор). Однако использование SMS в качестве второго фактора больше не рекомендуется. Для этого типа реализации существует слишком много известных векторов атак.
Настройка MFA для страниц администрирования с помощью ASP.NET Core Identity
MFA может быть вынуждена пользователям получать доступ к конфиденциальным страницам в приложении ASP.NET Core Identity . Это может быть полезно для приложений, где существуют различные уровни доступа для различных удостоверений. Например, пользователи могут просматривать данные профиля с помощью имени входа в систему паролей, но администратору потребуется использовать MFA для доступа к административным страницам.
Расширение имени входа с помощью утверждения MFA
Демонстрационный код настраивается с помощью ASP.NET Core и Identity Razor Pages. Метод AddIdentity
используется вместо AddDefaultIdentity
одного, поэтому IUserClaimsPrincipalFactory
реализацию можно использовать для добавления утверждений в identity после успешного входа.
Предупреждение
В этой статье показано использование строка подключения. С локальной базой данных пользователь не должен пройти проверку подлинности, но в рабочей среде строка подключения иногда включают пароль для проверки подлинности. Учетные данные владельца ресурса (ROPC) — это риск безопасности, который следует избежать в рабочих базах данных. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для приложений, развернутых в тестовых или рабочих средах, см. в разделе "Безопасные потоки проверки подлинности".
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();
}
Класс AdditionalUserClaimsPrincipalFactory
добавляет amr
утверждение к утверждениям пользователя только после успешного входа. Значение утверждения считывается из базы данных. Утверждение добавляется здесь, так как пользователь должен получить доступ только к более защищенному представлению, если identity он вошел в систему с помощью MFA. Если представление базы данных считывается из базы данных непосредственно вместо использования утверждения, то можно получить доступ к представлению без MFA непосредственно после активации 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 Так как настройка службы изменилась в Startup
классе, макеты Identity необходимо обновить. Создание шаблонов Identity страниц в приложение. Определите макет в Identity/Account/Manage/_Layout.cshtml
файле.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Кроме того, назначьте макет для всех страниц управления со Identity страниц:
@{
Layout = "_Layout.cshtml";
}
Проверка требования MFA на странице администрирования
Страница администрирования Razor проверяет, выполнил ли пользователь вход с помощью MFA. В методе OnGet
identity используется для доступа к утверждениям пользователя. Утверждение amr
проверяется для значения mfa
. identity Если это утверждение отсутствует или нетfalse
, страница перенаправляется на страницу "Включить MFA". Это возможно, так как пользователь уже вошел в систему, но без 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();
}
}
}
Логика пользовательского интерфейса для переключения сведений о входе пользователя
Политика авторизации была добавлена в файл программы. Для политики требуется amr
утверждение со значением mfa
.
builder.Services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Затем эту политику можно использовать в _Layout
представлении для отображения или скрытия меню администрирования с предупреждением:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Если вход identity в систему с помощью MFA выполнен, меню администрирования отображается без предупреждения подсказки. Когда пользователь выполнил вход без MFA, отображается меню администратора (не включено) вместе с подсказкой, которая сообщает пользователю (объясняя предупреждение).
@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>
}
}
Если пользователь входит в систему без MFA, отображается предупреждение:
Пользователь перенаправляется в режим включения MFA при нажатии ссылки администратора :
Отправка требования к входу MFA на сервер OpenID Connect
Этот acr_values
параметр можно использовать для передачи mfa
требуемого значения от клиента серверу в запросе проверки подлинности.
Примечание.
Этот acr_values
параметр необходимо обрабатывать на сервере OpenID Connect для работы.
Клиент OpenID Connect ASP.NET Core
Клиентское приложение OpenID Connect для ASP.NET Core Razor Pages использует AddOpenIdConnect
метод для входа на сервер OpenID Connect. Параметр acr_values
задается со значением mfa
и отправляется с помощью запроса проверки подлинности. Этот OpenIdConnectEvents
параметр используется для добавления.
Рекомендуемые значения параметров см. в разделе "Справочные acr_values
значения метода проверки подлинности".
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);
}
};
});
Пример сервера OpenID Connect IdentityServer 4 с ASP.NET Core Identity
На сервере OpenID Connect, который реализуется с помощью ASP.NET Core Identity с представлениями MVC, создается новое представление ErrorEnable2FA.cshtml
. Представление :
- Отображается, если Identity из приложения требуется многофакторная проверка подлинности, но пользователь не активировал это в Identity.
- Сообщает пользователю и добавляет ссылку для активации.
@{
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>
В методе Login
IIdentityServerInteractionService
реализация _interaction
интерфейса используется для доступа к параметрам запроса OpenID Connect. Доступ acr_values
к параметру AcrValues
осуществляется с помощью свойства. После отправки этого клиента с mfa
набором это можно проверить.
Если требуется MFA, и пользователь в ASP.NET Core Identity включил MFA, то имя входа продолжается. Если у пользователя нет многофакторной проверки подлинности, пользователь перенаправляется в пользовательское представление ErrorEnable2FA.cshtml
. Затем ASP.NET Core Identity войдите в систему пользователя.
//
// 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
Метод ExternalLoginCallback
работает так же, как локальное Identity имя входа. Свойство AcrValues
проверяется для mfa
значения. mfa
Если значение присутствует, многофакторная проверка подлинности принудительно выполняется до завершения входа (например, перенаправление в 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
Если пользователь уже вошел в систему, клиентское приложение:
- По-прежнему
amr
проверяет утверждение. - Может настроить MFA со ссылкой на представление ASP.NET Core Identity .
Принудительное использование клиента OpenID Connect для ASP.NET Core, требуемого многофакторной проверки подлинности
В этом примере показано, как приложение ASP.NET Core Razor Page, использующее OpenID Connect для входа, может требовать, чтобы пользователи прошли проверку подлинности с помощью MFA.
Чтобы проверить требование MFA, IAuthorizationRequirement
создается требование. Это будет добавлено на страницы с помощью политики, требующей многофакторной проверки подлинности.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc
{
public class RequireMfa : IAuthorizationRequirement{}
}
Реализуется AuthorizationHandler
, который будет использовать amr
утверждение и проверять значение mfa
. Возвращается amr
в id_token
успешной проверке подлинности и может иметь множество различных значений, как определено в спецификации ссылочных значений метода проверки подлинности.
Возвращаемое значение зависит от способа identity проверки подлинности и реализации сервера OpenID Connect.
RequireMfa
Использует AuthorizationHandler
требование и проверяет amr
утверждение. Сервер OpenID Connect можно реализовать с помощью IdentityServer4 с ASP.NET Core Identity. Когда пользователь входит в систему с помощью TOTP, amr
утверждение возвращается со значением MFA. Если используется другая реализация сервера OpenID Connect или другой тип MFA, amr
утверждение будет или может иметь другое значение. Код должен быть расширен, чтобы принять это, а также.
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;
}
}
В методе Startup.ConfigureServices
AddOpenIdConnect
метод используется в качестве схемы вызовов по умолчанию. Обработчик авторизации, используемый для проверки amr
утверждения, добавляется в контейнер Inversion of Control. Затем создается политика, которая добавляет 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();
}
Затем эта политика используется на Razor странице по мере необходимости. Политику можно добавить глобально для всего приложения.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Если пользователь проходит проверку подлинности без MFA, утверждение, вероятно, amr
будет иметь pwd
значение. Запрос не будет авторизован для доступа к странице. Используя значения по умолчанию, пользователь будет перенаправлен на страницу Account/AccessDenied . Это поведение можно изменить или реализовать собственную пользовательскую логику здесь. В этом примере добавляется ссылка, чтобы допустимый пользователь смог настроить MFA для своей учетной записи.
@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>
Теперь только пользователи, прошедшие проверку подлинности с помощью MFA, могут получить доступ к странице или веб-сайту. Если используются разные типы MFA или если 2FA хорошо, amr
утверждение будет иметь разные значения и должны быть обработаны правильно. Разные серверы OpenID Connect также возвращают разные значения для этого утверждения и могут не соответствовать спецификации ссылочных значений метода проверки подлинности.
При входе без MFA (например, с помощью пароля):
pwd
Имеетamr
значение:Доступ запрещен:
Кроме того, войдите в систему с помощью OTP:Identity
Дополнительные ресурсы
ASP.NET Core