Поделиться через


Введение в 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 Identity Server в производственной среде. Дополнительные сведения см. в статье Миграция с ASP.NET Core 5.0 на 6.0.

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

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

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

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

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

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

  • /Identity/Аккаунт/Вход
  • /Identity/Account/Logout
  • /Identity/Аккаунт/Управление

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

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

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

Update-Database

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

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

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

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

Контекстное меню таблицы AspNetUsers в обозревателе объектов SQL Server

Настройка 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, Login, LogOut и RegisterConfirmation. Следуйте идентификатору шаблона в проекте 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 Компоненты

Все пакеты 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>

Следующие шаги

Автор: Рик Андерсон (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 IdentityServer — это платформа OpenID Connect и OAuth 2.0 для ASP.NET Core. Duende IdentityServer включает следующие функции безопасности:

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

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

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

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

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

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

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

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

  • /Identity/Аккаунт/Войти
  • /Identity/Account/Logout
  • /Identity/Аккаунт/Управление

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

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

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

PM> Update-Database

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

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

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

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

Контекстное меню в таблице AspNetUsers в Обозревателе объектов SQL Server

Настройка 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. добавляет посредническое ПО для проверки подлинности в конвейер запросов.

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 должен вызываться в порядке, приведенном в предыдущем коде.

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

Шаблон регистрации, входа в систему, выхода из системы и подтверждения регистрации

Добавьте файлы Register, Login, LogOut и RegisterConfirmation. Следуйте идентификатору шаблона в проекте 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 Компоненты

Все пакеты 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>

Следующие шаги