Общие сведения о Identity ASP.NET Core

Автор: Рик Андерсон (Rick Anderson)

ASP.NET Core Identity:

  • Api, поддерживающий функции входа в пользовательский интерфейс.
  • Управляет пользователями, паролями, данными профиля, ролями, утверждениями, маркерами, подтверждением электронной почты и т. д.

Пользователи могут создать учетную запись с данными для входа, хранящимися в Identity ней, или использовать внешний поставщик входа. Поддерживаемые внешние поставщики входа включают Facebook, Google, Учетную запись Майкрософт и Twitter.

Дополнительные сведения о том, как глобально требовать проверку подлинности всех пользователей, см. в разделе Требовать проверку подлинности пользователей.

Исходный Identity код доступен на сайте GitHub. Identity Шаблон и просмотр созданных файлов для просмотра взаимодействия с Identityшаблоном.

Identity обычно настраивается с помощью базы данных SQL Server для хранения имен пользователей, паролей и данных профиля. Кроме того, можно использовать другое постоянное хранилище, например таблицу Azure служба хранилища.

В этом разделе описано, как Identity зарегистрировать, войти и выйти из него. Примечание. Шаблоны обрабатывают имя пользователя и электронную почту так же, как и для пользователей. Дополнительные инструкции по созданию приложений, которые используются Identity, см. в разделе "Дальнейшие действия".

ASP.NET Core Identity не связан с платформа удостоверений Майкрософт. платформа удостоверений Майкрософт:

  • Эволюция платформы разработчиков Azure Active Directory (Azure AD).
  • Альтернативное решение для идентификации и авторизации в приложениях ASP.NET Core.

ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:

Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:

  • Проверка подлинности как услуга (AaaS)
  • Единый вход (SSO) для нескольких типов приложений
  • Контроль доступа для API
  • Шлюз федерации

Важно!

Компания Duende Software может потребовать лицензионный сбор за использование Duende IdentityServer в рабочей среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.

Дополнительные сведения см. в документации по Duende Identity Server (на веб-сайте ПО Duende).

Просмотр или скачивание примера кода (как скачать).

Создание веб-приложения с проверкой подлинности

Создайте проект веб-приложения ASP.NET Core с отдельными учетными записями пользователей.

  • Выберите шаблон Веб-приложение ASP.NET Core. Назовите проект WebApp1 тем же пространством имен, что и скачивание проекта. Щелкните OK.
  • В поле входных данных Тип проверки подлинности выберите Отдельные учетные записи пользователей.

Созданный проект предоставляет ASP.NET CoreIdentityв виде библиотеки Razorклассов. Библиотека IdentityRazor классов предоставляет конечные точки с областью Identity . Например:

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

Применение миграции

Примените миграции для инициализации базы данных.

Выполните следующую команду в консоли диспетчер пакетов (PMC):

Update-Database

Проверка регистрации и входа

Запустите приложение и зарегистрируйте пользователя. В зависимости от размера экрана может потребоваться выбрать кнопку переключателя навигации, чтобы просмотреть ссылки "Регистрация и вход ".

Identity Просмотр базы данных

  • В меню "Вид" выберите SQL Server обозреватель объектов (SSOX).
  • Перейдите к (localdb)MSSQLLocalDB(SQL Server 13). Щелкните правой кнопкой мыши dbo. AspNetUsers>view Data:

Contextual menu on AspNetUsers table in SQL Server Object Explorer

Настройка Identity служб

Службы добавляются в Program.cs. Типичным шаблоном является вызов методов в следующем порядке:

  1. Add{Service}
  2. builder.Services.Configure{Service}
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebApp1.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.Configure<IdentityOptions>(options =>
{
    // Password settings.
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    options.Password.RequireNonAlphanumeric = true;
    options.Password.RequireUppercase = true;
    options.Password.RequiredLength = 6;
    options.Password.RequiredUniqueChars = 1;

    // Lockout settings.
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;

    // User settings.
    options.User.AllowedUserNameCharacters =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
    options.User.RequireUniqueEmail = false;
});

builder.Services.ConfigureApplicationCookie(options =>
{
    // Cookie settings
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

    options.LoginPath = "/Identity/Account/Login";
    options.AccessDeniedPath = "/Identity/Account/AccessDenied";
    options.SlidingExpiration = true;
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

Предыдущий код настраивается Identity со значениями параметров по умолчанию. Службы становятся доступными для приложения с помощью внедрения зависимостей.

Identity включен путем вызова UseAuthentication. UseAuthenticationдобавляет ПО промежуточного слоя проверки подлинности в конвейер запросов.

Созданное шаблоном приложение не использует авторизацию. app.UseAuthorization включается, чтобы убедиться, что он добавлен в правильном порядке, если приложение добавит авторизацию. UseRouting, UseAuthenticationи UseAuthorization должен вызываться в порядке, приведенном в приведенном выше коде.

Дополнительные сведения см. в IdentityOptionsразделе IdentityOptions и запуске приложения.

Шаблон Register, Login, LogOut и RegisterConfirmation

RegisterДобавьте , и LogOutLoginRegisterConfirmation файлы. Следуйте инструкциям по созданию кода, показанного в этом разделе, следуйте удостоверению шаблона в Razor проекте с инструкциями по авторизации.

Проверка регистра

Когда пользователь нажимает кнопку "Зарегистрировать" на Register странице, RegisterModel.OnPostAsync вызывается действие. Пользователь создается CreateAsync(TUser) в объекте _userManager :

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
                                          .ToList();
    if (ModelState.IsValid)
    {
        var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
        var result = await _userManager.CreateAsync(user, Input.Password);
        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            if (_userManager.Options.SignIn.RequireConfirmedAccount)
            {
                return RedirectToPage("RegisterConfirmation", 
                                      new { email = Input.Email });
            }
            else
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Отключение проверки учетной записи по умолчанию

При использовании шаблонов по умолчанию пользователь перенаправляется на Account.RegisterConfirmation место, где можно выбрать ссылку, чтобы подтвердить учетную запись. Значение по умолчанию Account.RegisterConfirmation используется только для тестирования, автоматическая проверка учетной записи должна быть отключена в рабочем приложении.

Чтобы требовать подтвержденную учетную запись и предотвратить немедленный вход при регистрации, задайте DisplayConfirmAccountLink = false в /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs:

[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IEmailSender _sender;

    public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
    {
        _userManager = userManager;
        _sender = sender;
    }

    public string Email { get; set; }

    public bool DisplayConfirmAccountLink { get; set; }

    public string EmailConfirmationUrl { get; set; }

    public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
    {
        if (email == null)
        {
            return RedirectToPage("/Index");
        }

        var user = await _userManager.FindByEmailAsync(email);
        if (user == null)
        {
            return NotFound($"Unable to load user with email '{email}'.");
        }

        Email = email;
        // Once you add a real email sender, you should remove this code that lets you confirm the account
        DisplayConfirmAccountLink = false;
        if (DisplayConfirmAccountLink)
        {
            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            EmailConfirmationUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);
        }

        return Page();
    }
}

Вход в систему

Форма входа отображается в следующих случаях:

  • Выбрана ссылка на вход .
  • Пользователь пытается получить доступ к ограниченной странице, к ней не разрешен доступ или когда он не прошел проверку подлинности в системе.

При отправке OnPostAsync формы на странице входа вызывается действие. PasswordSignInAsync вызывается для _signInManager объекта.

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email,
                           Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new
            {
                ReturnUrl = returnUrl,
                RememberMe = Input.RememberMe
            });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Сведения о том, как принимать решения об авторизации, см. в разделе "Введение в авторизацию" в ASP.NET Core.

Выход

Ссылка выхода вызывает LogoutModel.OnPost действие.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace WebApp1.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class LogoutModel : PageModel
    {
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly ILogger<LogoutModel> _logger;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation("User logged out.");
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                return RedirectToPage();
            }
        }
    }
}

В приведенном выше коде код return RedirectToPage(); должен быть перенаправлен, чтобы браузер выполнял новый запрос, а удостоверение пользователя обновляется.

SignOutAsync очищает утверждения пользователя, хранящиеся в объекте cookie.

Запись указана в следующих параметрах Pages/Shared/_LoginPartial.cshtml:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
        <a  class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" 
                                              title="Manage">Hello @User.Identity.Name!</a>
    </li>
    <li class="nav-item">
        <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" 
                                  asp-route-returnUrl="@Url.Page("/", new { area = "" })" 
                                  method="post" >
            <button  type="submit" class="nav-link btn btn-link text-dark">Logout</button>
        </form>
    </li>
}
else
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
}
</ul>

Тест Identity

Шаблоны веб-проектов по умолчанию разрешают анонимный доступ к домашним страницам. Чтобы проверить Identity, добавьте [Authorize]:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace WebApp1.Pages
{
    [Authorize]
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

Если вы вошли, выйдите из нее. Запустите приложение и выберите ссылку Privacy . Вы перейдете на страницу входа.

Изучение Identity

Дополнительные сведения см. в следующем Identity разделе:

Identity Components

Все пакеты NuGet, зависящие от зависимогоIdentity, включены в общую платформу ASP.NET Core.

Основной пакет для Identity этого является Microsoft.AspNetCore.Identity. Этот пакет содержит основной набор интерфейсов для ASP.NET Core Identityи включается Microsoft.AspNetCore.Identity.EntityFrameworkCoreв него.

Миграция на ASP.NET Core Identity

Дополнительные сведения и рекомендации по переносу существующего Identity хранилища см. в разделе "Миграция проверки подлинности" и Identity"Миграция".

Настройка надежности пароля

См . пример конфигурации , который задает минимальные требования к паролям.

AddDefaultIdentity и AddIdentity

AddDefaultIdentity появилась в ASP.NET Core 2.1. Вызов аналогичен вызову AddDefaultIdentity следующего:

Дополнительные сведения см. в источнике AddDefaultIdentity.

Запрет публикации статических Identity ресурсов

Чтобы предотвратить публикацию статических Identity ресурсов (таблиц стилей и файлов JavaScript для Identity пользовательского интерфейса) в корневой веб-сайт, добавьте следующее ResolveStaticWebAssetsInputsDependsOn свойство и RemoveIdentityAssets целевой объект в файл проекта приложения:

<PropertyGroup>
  <ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>

<Target Name="RemoveIdentityAssets">
  <ItemGroup>
    <StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
  </ItemGroup>
</Target>

Next Steps

Автор: Рик Андерсон (Rick Anderson)

ASP.NET Core Identity:

  • Api, поддерживающий функции входа в пользовательский интерфейс.
  • Управляет пользователями, паролями, данными профиля, ролями, утверждениями, маркерами, подтверждением электронной почты и т. д.

Пользователи могут создать учетную запись с данными для входа, хранящимися в Identity ней, или использовать внешний поставщик входа. Поддерживаемые внешние поставщики входа включают Facebook, Google, Учетную запись Майкрософт и Twitter.

Дополнительные сведения о том, как глобально требовать проверку подлинности всех пользователей, см. в разделе Требовать проверку подлинности пользователей.

Исходный Identity код доступен на сайте GitHub. Identity Шаблон и просмотр созданных файлов для просмотра взаимодействия с Identityшаблоном.

Identity обычно настраивается с помощью базы данных SQL Server для хранения имен пользователей, паролей и данных профиля. Кроме того, можно использовать другое постоянное хранилище, например таблицу Azure служба хранилища.

В этом разделе описано, как Identity зарегистрировать, войти и выйти из него. Примечание. Шаблоны обрабатывают имя пользователя и электронную почту так же, как и для пользователей. Дополнительные инструкции по созданию приложений, которые используются Identity, см. в разделе "Дальнейшие действия".

платформа удостоверений Майкрософт:

  • Эволюция платформы разработчиков Azure Active Directory (Azure AD).
  • Альтернативное решение для идентификации и авторизации в приложениях ASP.NET Core.
  • Не связан с ASP.NET Core Identity.

ASP.NET Core Identity позволяет использовать функцию входа в пользовательском интерфейсе для веб-приложений ASP.NET Core. Чтобы защитить веб-API и одностраничные приложения, используйте один из следующих способов:

Duende Identity Server — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende Identity Server включает следующие функции безопасности:

  • Проверка подлинности как услуга (AaaS)
  • Единый вход (SSO) для нескольких типов приложений
  • Контроль доступа для API
  • Шлюз федерации

Дополнительные сведения см. в разделе "Обзор сервера DuendeIdentity".

Дополнительные сведения о других поставщиках проверки подлинности см. в разделе "Параметры проверки подлинности Community OSS" для ASP.NET Core

Просмотр или скачивание примера кода (как скачать).

Создание веб-приложения с проверкой подлинности

Создайте проект веб-приложения ASP.NET Core с отдельными учетными записями пользователей.

  • Выберите File>New>Project ( Файл > Создать > Проект).
  • Выберите Веб-приложение ASP.NET Core. Назовите проект WebApp1 тем же пространством имен, что и скачивание проекта. Щелкните OK.
  • Выберите веб-приложение ASP.NET Core, а затем нажмите кнопку "Изменить проверку подлинности".
  • Выберите отдельные учетные записи пользователей и нажмите кнопку "ОК".

Созданный проект предоставляет ASP.NET CoreIdentityв виде библиотеки Razorклассов. Библиотека IdentityRazor классов предоставляет конечные точки с областью Identity . Например:

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

Применение миграции

Примените миграции для инициализации базы данных.

Выполните следующую команду в консоли диспетчер пакетов (PMC):

PM> Update-Database

Проверка регистрации и входа

Запустите приложение и зарегистрируйте пользователя. В зависимости от размера экрана может потребоваться выбрать кнопку переключателя навигации, чтобы просмотреть ссылки "Регистрация и вход ".

Identity Просмотр базы данных

  • В меню "Вид" выберите SQL Server обозреватель объектов (SSOX).
  • Перейдите к (localdb)MSSQLLocalDB(SQL Server 13). Щелкните правой кнопкой мыши dbo. AspNetUsers>view Data:

Contextual menu on AspNetUsers table in SQL Server Object Explorer

Настройка Identity служб

Службы добавляются в ConfigureServices. По стандартному шаблону сначала вызываются все методы Add{Service}, а затем все методы services.Configure{Service}.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
     // options.UseSqlite(
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings.
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;

        // Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;

        // User settings.
        options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
        options.User.RequireUniqueEmail = false;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

        options.LoginPath = "/Identity/Account/Login";
        options.AccessDeniedPath = "/Identity/Account/AccessDenied";
        options.SlidingExpiration = true;
    });
}

Предыдущий выделенный код настраивается Identity со значениями параметров по умолчанию. Службы становятся доступными для приложения с помощью внедрения зависимостей.

Identity включен путем вызова UseAuthentication. UseAuthenticationдобавляет ПО промежуточного слоя проверки подлинности в конвейер запросов.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        // options.UseSqlite(
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDatabaseDeveloperPageExceptionFilter();
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings.
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;

        // Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;

        // User settings.
        options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
        options.User.RequireUniqueEmail = false;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

        options.LoginPath = "/Identity/Account/Login";
        options.AccessDeniedPath = "/Identity/Account/AccessDenied";
        options.SlidingExpiration = true;
    });
}

Предыдущий код настраивается Identity со значениями параметров по умолчанию. Службы становятся доступными для приложения с помощью внедрения зависимостей.

Identity включен путем вызова UseAuthentication. UseAuthenticationдобавляет ПО промежуточного слоя проверки подлинности в конвейер запросов.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Созданное шаблоном приложение не использует авторизацию. app.UseAuthorization включается, чтобы убедиться, что он добавлен в правильном порядке, если приложение добавит авторизацию. UseRouting, UseAuthentication, UseAuthorizationи UseEndpoints должен вызываться в порядке, приведенном в предыдущем коде.

Дополнительные сведения и IdentityOptionsStartupсведения см. в разделе IdentityOptions " Запуск приложения".

Шаблон Register, Login, LogOut и RegisterConfirmation

RegisterДобавьте , и LogOutLoginRegisterConfirmation файлы. Следуйте инструкциям по созданию кода, показанного в этом разделе, следуйте удостоверению шаблона в Razor проекте с инструкциями по авторизации.

Проверка регистра

Когда пользователь нажимает кнопку "Зарегистрировать" на Register странице, RegisterModel.OnPostAsync вызывается действие. Пользователь создается CreateAsync(TUser) в объекте _userManager :

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
                                          .ToList();
    if (ModelState.IsValid)
    {
        var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
        var result = await _userManager.CreateAsync(user, Input.Password);
        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            if (_userManager.Options.SignIn.RequireConfirmedAccount)
            {
                return RedirectToPage("RegisterConfirmation", 
                                      new { email = Input.Email });
            }
            else
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Отключение проверки учетной записи по умолчанию

При использовании шаблонов по умолчанию пользователь перенаправляется на Account.RegisterConfirmation место, где можно выбрать ссылку, чтобы подтвердить учетную запись. Значение по умолчанию Account.RegisterConfirmation используется только для тестирования, автоматическая проверка учетной записи должна быть отключена в рабочем приложении.

Чтобы требовать подтвержденную учетную запись и предотвратить немедленный вход при регистрации, задайте DisplayConfirmAccountLink = false в /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs:

[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IEmailSender _sender;

    public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
    {
        _userManager = userManager;
        _sender = sender;
    }

    public string Email { get; set; }

    public bool DisplayConfirmAccountLink { get; set; }

    public string EmailConfirmationUrl { get; set; }

    public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
    {
        if (email == null)
        {
            return RedirectToPage("/Index");
        }

        var user = await _userManager.FindByEmailAsync(email);
        if (user == null)
        {
            return NotFound($"Unable to load user with email '{email}'.");
        }

        Email = email;
        // Once you add a real email sender, you should remove this code that lets you confirm the account
        DisplayConfirmAccountLink = false;
        if (DisplayConfirmAccountLink)
        {
            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            EmailConfirmationUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);
        }

        return Page();
    }
}

Вход в систему

Форма входа отображается в следующих случаях:

  • Выбрана ссылка на вход .
  • Пользователь пытается получить доступ к ограниченной странице, к ней не разрешен доступ или когда он не прошел проверку подлинности в системе.

При отправке OnPostAsync формы на странице входа вызывается действие. PasswordSignInAsync вызывается для _signInManager объекта.

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email,
                           Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new
            {
                ReturnUrl = returnUrl,
                RememberMe = Input.RememberMe
            });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

Сведения о том, как принимать решения об авторизации, см. в разделе "Введение в авторизацию" в ASP.NET Core.

Выход

Ссылка выхода вызывает LogoutModel.OnPost действие.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace WebApp1.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class LogoutModel : PageModel
    {
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly ILogger<LogoutModel> _logger;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation("User logged out.");
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                return RedirectToPage();
            }
        }
    }
}

В приведенном выше коде код return RedirectToPage(); должен быть перенаправлен, чтобы браузер выполнял новый запрос, а удостоверение пользователя обновляется.

SignOutAsync очищает утверждения пользователя, хранящиеся в объекте cookie.

Запись указана в следующих параметрах Pages/Shared/_LoginPartial.cshtml:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
        <a  class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" 
                                              title="Manage">Hello @User.Identity.Name!</a>
    </li>
    <li class="nav-item">
        <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" 
                                  asp-route-returnUrl="@Url.Page("/", new { area = "" })" 
                                  method="post" >
            <button  type="submit" class="nav-link btn btn-link text-dark">Logout</button>
        </form>
    </li>
}
else
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
}
</ul>

Тест Identity

Шаблоны веб-проектов по умолчанию разрешают анонимный доступ к домашним страницам. Чтобы проверить Identity, добавьте [Authorize]:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace WebApp1.Pages
{
    [Authorize]
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

Если вы вошли, выйдите из нее. Запустите приложение и выберите ссылку Privacy . Вы перейдете на страницу входа.

Изучение Identity

Дополнительные сведения см. в следующем Identity разделе:

Identity Components

Все пакеты NuGet, зависящие от зависимогоIdentity, включены в общую платформу ASP.NET Core.

Основной пакет для Identity этого является Microsoft.AspNetCore.Identity. Этот пакет содержит основной набор интерфейсов для ASP.NET Core Identityи включается Microsoft.AspNetCore.Identity.EntityFrameworkCoreв него.

Миграция на ASP.NET Core Identity

Дополнительные сведения и рекомендации по переносу существующего Identity хранилища см. в разделе "Миграция проверки подлинности" и Identity"Миграция".

Настройка надежности пароля

См . пример конфигурации , который задает минимальные требования к паролям.

Запрет публикации статических Identity ресурсов

Чтобы предотвратить публикацию статических Identity ресурсов (таблиц стилей и файлов JavaScript для Identity пользовательского интерфейса) в корневой веб-сайт, добавьте следующее ResolveStaticWebAssetsInputsDependsOn свойство и RemoveIdentityAssets целевой объект в файл проекта приложения:

<PropertyGroup>
  <ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>

<Target Name="RemoveIdentityAssets">
  <ItemGroup>
    <StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
  </ItemGroup>
</Target>

Next Steps