Как защитить Identity серверную часть веб-API для spAs

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в статье о политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

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

В этой статье показано, как защитить Identity серверную часть веб-API для таких служб, как Angular, React и Vue. Те же интерфейсы API серверной части можно использовать для защиты Blazor WebAssembly приложений.

Необходимые компоненты

Действия, описанные в этой статье, добавляют проверку подлинности и авторизацию в приложение ASP.NET Core Web API, которое:

  • Не настроено для проверки подлинности.
  • Целевые объекты или более поздние net8.0 версии.
  • Может быть минимальным API или API на основе контроллера.

Некоторые инструкции по тестированию в этой статье используют пользовательский интерфейс Swagger, включенный в шаблон проекта. Пользовательский интерфейс Swagger не требуется использовать Identity с серверной частью веб-API.

Установка пакетов Nuget

Установите следующие пакеты NuGet:

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

Измените базу данных позже на SQLite или SQL Server, чтобы сохранить данные пользователей между сеансами при тестировании или использовании в рабочей среде. Это приводит к некоторой сложности по сравнению с памятью, так как требуется, чтобы база данных была создана с помощью миграций, как показано в руководстве по началу EF Core работы.

Установите эти пакеты с помощью диспетчера пакетов NuGet в Visual Studio или команды dotnet add package CLI.

Создайте IdentityDbContext.

Добавление класса с именем ApplicationDbContext , наследуемого от IdentityDbContext<TUser>:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) :
        base(options)
    { }
}

Показанный код предоставляет специальный конструктор, позволяющий настроить базу данных для разных сред.

При добавлении кода, показанного на этих шагах, добавьте одну или несколько следующих using директив.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

Настройка контекста EF Core

Как отмечалось ранее, самый простой способ начать работу — использовать базу данных в памяти. При использовании памяти каждый запуск начинается с новой базы данных, и нет необходимости использовать миграции. После вызова WebApplication.CreateBuilder(args)добавьте следующий код, чтобы настроить Identity использование базы данных в памяти:

builder.Services.AddDbContext<ApplicationDbContext>(
    options => options.UseInMemoryDatabase("AppDb"));

Чтобы сохранить данные пользователей между сеансами при тестировании или использовании в рабочей среде, измените базу данных позже на SQLite или SQL Server.

Добавление Identity служб в контейнер

После вызова WebApplication.CreateBuilder(args)вызов вызовите AddAuthorization добавление служб в контейнер внедрения зависимостей (DI):

builder.Services.AddAuthorization();

Активация Identity API

После вызова, вызова WebApplication.CreateBuilder(args)AddIdentityApiEndpoints<TUser>(IServiceCollection) и AddEntityFrameworkStores<TContext>(IdentityBuilder).

builder.Services.AddIdentityApiEndpoints<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

По умолчанию активируются как файлы cookie, так и частные маркеры. Файлы cookie и маркеры выдаются при входе, если useCookies параметр строки запроса в конечной точке входа .true

Маршруты карты Identity

После вызова builder.Build()вызовите MapIdentityApi<TUser>(IEndpointRouteBuilder) для сопоставления Identity конечных точек:

app.MapIdentityApi<IdentityUser>();

Защита выбранных конечных точек

Чтобы защитить конечную точку, используйте RequireAuthorization метод расширения для Map{Method} вызова, определяющего маршрут. Например:

app.MapGet("/weatherforecast", (HttpContext httpContext) =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = summaries[Random.Shared.Next(summaries.Length)]
        })
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi()
.RequireAuthorization();

Метод RequireAuthorization также можно использовать для:

  • Защита конечных точек пользовательского интерфейса Swagger, как показано в следующем примере:

    app.MapSwagger().RequireAuthorization();
    
  • Защита с определенным утверждением или разрешением, как показано в следующем примере:

    .RequireAuthorization("Admin");
    

В проекте веб-API на основе контроллера защита конечных точек путем применения атрибута [Authorize] к контроллеру или действию.

Проверка API

Быстрый способ проверки подлинности — использовать базу данных в памяти и пользовательский интерфейс Swagger, включенный в шаблон проекта. Ниже показано, как протестировать API с помощью пользовательского интерфейса Swagger. Убедитесь, что конечные точки пользовательского интерфейса Swagger не защищены.

Попытка доступа к защищенной конечной точке

  • Запустите приложение и перейдите к пользовательскому интерфейсу Swagger.
  • Разверните безопасную конечную точку, например /weatherforecast в проекте, созданном шаблоном веб-API.
  • Выберите Опробовать.
  • Выберите Выполнить. Ответ имеет значение 401 - not authorized.

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

  • Разверните /register и выберите "Попробовать".

  • В разделе "Параметры" пользовательского интерфейса показан пример текста запроса:

    {
      "email": "string",
      "password": "string"
    }
    
  • Замените "string" допустимым адресом электронной почты и паролем, а затем нажмите кнопку "Выполнить".

    Чтобы соответствовать правилам проверки паролей по умолчанию, пароль должен иметь по крайней мере шесть символов и содержать по крайней мере один из следующих символов:

    • Буква в верхнем регистре
    • Буква в нижнем регистре
    • Числовое числовой цифры
    • Неэлементный символ

    Если ввести недопустимый адрес электронной почты или неправильный пароль, результат содержит ошибки проверки. Ниже приведен пример текста ответа с ошибками проверки:

    {
      "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
      "title": "One or more validation errors occurred.",
      "status": 400,
      "errors": {
        "PasswordTooShort": [
          "Passwords must be at least 6 characters."
        ],
        "PasswordRequiresNonAlphanumeric": [
          "Passwords must have at least one non alphanumeric character."
        ],
        "PasswordRequiresDigit": [
          "Passwords must have at least one digit ('0'-'9')."
        ],
        "PasswordRequiresLower": [
          "Passwords must have at least one lowercase ('a'-'z')."
        ]
      }
    }
    

    Ошибки возвращаются в формате ProblemDetails , чтобы клиент смог проанализировать их и отобразить ошибки проверки по мере необходимости.

    Успешная регистрация приводит к ответу 200 - OK .

Проверка имени входа

  • Разверните /login и выберите " Попробовать". В тексте запроса примера показаны два дополнительных параметра:

    {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
      "twoFactorRecoveryCode": "string"
    }
    

    Дополнительные свойства JSON не требуются для этого примера и могут быть удалены. Задайте для параметра useCookies значение true.

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

    Успешное имя входа приводит к ответу 200 - OK с заголовком cookie ответа.

Повторное тестирование защищенной конечной точки

После успешного входа повторно запустите безопасную конечную точку. Проверка подлинности cookie автоматически отправляется с запросом, и конечная точка авторизована. Cookie-основанная проверка подлинности безопасно встроена в браузер и "просто работает".

Тестирование с помощью клиентов nonbrowser

Некоторые веб-клиенты могут не включать файлы cookie в заголовок по умолчанию:

  • Если вы используете средство для тестирования API, может потребоваться включить файлы cookie в параметрах.

  • API JavaScript fetch по умолчанию не включает файлы cookie. Включите их, задав credentials значение include в параметрах.

  • Выполняющийся HttpClient в Blazor WebAssembly приложении должен HttpRequestMessage включать учетные данные, как показано в следующем примере:

    request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);
    

Использование проверки подлинности на основе маркеров безопасности

Мы рекомендуем использовать файлы cookie в приложениях на основе браузера, так как по умолчанию браузер автоматически обрабатывает их без предоставления им доступа к JavaScript.

Выдается пользовательский маркер (который является владельцем платформы ASP.NET Core identity ), который можно использовать для проверки подлинности последующих запросов. Маркер передается в заголовке Authorization в качестве маркера носителя. Также предоставляется маркер обновления. Этот маркер позволяет приложению запрашивать новый маркер, когда срок действия старого маркера истекает без повторного входа пользователя.

Маркеры не являются стандартными веб-токенами JSON (JWTs). Использование пользовательских маркеров намеренно, так как встроенный Identity API предназначен в первую очередь для простых сценариев. Параметр токена не предназначен для полнофункционированного identity поставщика услуг или сервера токенов, а вместо этого альтернативой cookie для клиентов, которые не могут использовать файлы cookie.

Чтобы использовать проверку подлинности на основе маркеров, задайте useCookies параметр строки запроса для false вызова конечной /login точки. Маркеры используют схему проверки подлинности носителя . С помощью маркера, возвращаемого из вызова /login, последующие вызовы защищенных конечных точек должны добавить заголовок Authorization: Bearer <token> , где <token> находится маркер доступа. Дополнительные сведения см. в разделе "Использование конечной POST /login точки " далее в этой статье.

Выход

Чтобы предоставить пользователю способ выхода из системы, определите конечную /logout точку, как показано в следующем примере:

app.MapPost("/logout", async (SignInManager<IdentityUser> signInManager,
    [FromBody] object empty) =>
{
    if (empty != null)
    {
        await signInManager.SignOutAsync();
        return Results.Ok();
    }
    return Results.Unauthorized();
})
.WithOpenApi()
.RequireAuthorization();

Укажите пустой объект JSON ({}) в тексте запроса при вызове этой конечной точки. Следующий код является примером вызова конечной точки выхода:

public signOut() {
  return this.http.post('/logout', {}, {
    withCredentials: true,
    observe: 'response',
    responseType: 'text'

Конечные MapIdentityApi<TUser> точки

Вызов для MapIdentityApi<TUser> добавления следующих конечных точек в приложение:

Использование конечной POST /register точки

Текст запроса должен иметь Email и Password свойства:

{
  "email": "string",
  "password": "string",
}

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

Использование конечной POST /login точки

В тексте Email запроса и Password обязательны. Если включена TwoFactorCode TwoFactorRecoveryCode двухфакторная проверка подлинности (2FA), либо требуется. Если 2FA не включена, опустите оба twoFactorCode и twoFactorRecoveryCode. Дополнительные сведения см. в разделе "Использование конечной POST /manage/2fa точки " далее в этой статье.

Вот пример текста запроса с 2FA не включен:

{
  "email": "string",
  "password": "string"
}

Ниже приведены примеры текста запроса с включенным 2FA:

  • {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
    }
    
  • {
      "email": "string",
      "password": "string",
      "twoFactorRecoveryCode": "string"
    }
    

Конечная точка ожидает параметр строки запроса:

  • useCookies — Задано значение true для cookieпроверки подлинности на основе. Задайте значение false или опущено для проверки подлинности на основе маркеров.

Дополнительные сведения о cookieпроверке подлинности на основе см. в разделе "Проверка входа" ранее в этой статье.

Проверка подлинности на основе токенов

Если useCookies задано false или опущено, проверка подлинности на основе маркеров включена. Текст ответа содержит следующие свойства:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

Дополнительные сведения об этих свойствах см. в разделе AccessTokenResponse.

Поместите маркер доступа в заголовок, чтобы выполнить прошедшие проверку подлинности запросы, как показано в следующем примере.

Authorization: Bearer {access token}

Когда срок действия маркера доступа истекает, вызовите конечную точку /refresh .

Использование конечной POST /refresh точки

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

Текст запроса содержит только текст RefreshTokenзапроса. Ниже приведен пример текста запроса:

{
  "refreshToken": "string"
}

Если вызов выполнен успешно, текст ответа является новым AccessTokenResponse, как показано в следующем примере:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

Использование конечной GET /confirmEmail точки

Если Identity настроено подтверждение электронной почты, успешный вызов /register конечной точки отправляет сообщение электронной почты, содержащее ссылку на /confirmEmail конечную точку. Ссылка содержит следующие параметры строки запроса:

  • userId
  • code
  • changedEmail — включается только в том случае, если пользователь изменил адрес электронной почты во время регистрации.

Identity предоставляет текст по умолчанию для сообщения электронной почты подтверждения. По умолчанию тема электронной почты — "Подтверждение электронной почты", а текст электронной почты выглядит следующим образом:

 Please confirm your account by <a href='https://contoso.com/confirmEmail?userId={user ID}&code={generated code}&changedEmail={new email address}'>clicking here</a>.

RequireConfirmedEmail Если для свойства задано trueзначение, пользователь не сможет войти, пока адрес электронной почты не будет подтвержден, щелкнув ссылку в сообщении электронной почты. Конечная /confirmEmail точка:

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

Чтобы настроить Identity подтверждение электронной почты, добавьте код для Program.cs задания RequireConfirmedEmail true и добавьте класс, реализующий IEmailSender контейнер DI. Например:

builder.Services.Configure<IdentityOptions>(options =>
{
    options.SignIn.RequireConfirmedEmail = true;
});

builder.Services.AddTransient<IEmailSender, EmailSender>();

Дополнительные сведения см. в разделе "Подтверждение учетной записи" и восстановление паролей в ASP.NET Core.

Identity предоставляет текст по умолчанию для других сообщений электронной почты, которые необходимо отправить, например для сброса 2FA и пароля. Чтобы настроить эти сообщения электронной почты, предоставьте пользовательскую реализацию IEmailSender интерфейса. В предыдущем примере — это класс, EmailSender реализующий IEmailSender. Дополнительные сведения, включая пример класса, реализующего IEmailSender, см. в разделе "Подтверждение учетной записи" и восстановление паролей в ASP.NET Core.

Использование конечной POST /resendConfirmationEmail точки

Отправляет сообщение электронной почты только в том случае, если адрес действителен для зарегистрированного пользователя.

Текст запроса содержит только текст Emailзапроса. Ниже приведен пример текста запроса:

{
  "email": "string"
}

Дополнительные сведения см. в разделе "Использование конечной GET /confirmEmail точки " ранее в этой статье.

Использование конечной POST /forgotPassword точки

Создает сообщение электронной почты, содержащее код сброса пароля. Отправьте этот код /resetPassword в новый пароль.

Текст запроса содержит только текст Emailзапроса. Приведем пример:

{
  "email": "string"
}

Сведения о том, как включить Identity отправку сообщений электронной почты, см. в разделе "Использование конечной GET /confirmEmail точки".

Использование конечной POST /resetPassword точки

Вызовите эту конечную точку после получения кода сброса, вызвав конечную точку /forgotPassword .

Для текста запроса требуется Email, ResetCodeи NewPassword. Приведем пример:

{
  "email": "string",
  "resetCode": "string",
  "newPassword": "string"
}

Использование конечной POST /manage/2fa точки

Настраивает двухфакторную проверку подлинности (2FA) для пользователя. Если включена 2FA, для успешного входа требуется код, созданный приложением authenticator, в дополнение к адресу электронной почты и паролю.

Включить 2FA

Чтобы включить 2FA для текущего пользователя, прошедшего проверку подлинности, выполните следующие действия.

  • Вызовите конечную точку /manage/2fa , отправив пустой объект JSON ({}) в тексте запроса.

  • Текст отклика SharedKey предоставляет ряд других свойств, которые не нужны на данный момент. Общий ключ используется для настройки приложения authenticator. Пример текста отклика:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 0,
      "recoveryCodes": null,
      "isTwoFactorEnabled": false,
      "isMachineRemembered": false
    }
    
  • Используйте общий ключ, чтобы получить одноразовый пароль на основе времени (TOTP). Дополнительные сведения см. в разделе "Включение создания QR-кода" для приложений проверки подлинности TOTP в ASP.NET Core.

  • Вызовите конечную точку /manage/2fa , отправив TOTP и "enable": true в тексте запроса. Например:

    {
      "enable": true,
      "twoFactorCode": "string"
    }
    
  • Текст ответа подтверждает, что IsTwoFactorEnabled имеет значение true и предоставляет RecoveryCodes. Код восстановления используются для входа, если приложение authenticator недоступно. Пример текста ответа после успешного включения 2FA:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 10,
      "recoveryCodes": [
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string"
      ],
      "isTwoFactorEnabled": true,
      "isMachineRemembered": false
    }
    

Вход с помощью 2FA

Вызовите конечную точку /login , отправив адрес электронной почты, пароль и TOTP в тексте запроса. Например:

{
  "email": "string",
  "password": "string",
  "twoFactorCode": "string"
}

Если у пользователя нет доступа к приложению authenticator, войдите в систему, вызвав /login конечную точку с одним из код восстановления, предоставленных при включении 2FA. Текст запроса будет выглядеть как в следующем примере.

{
  "email": "string",
  "password": "string",
  "twoFactorRecoveryCode": "string"
}

Сброс код восстановления

Чтобы получить новую коллекцию код восстановления, вызовите эту конечную точку с ResetRecoveryCodes заданным значением true. Ниже приведен пример текста запроса:

{
  "resetRecoveryCodes": true
}

Сброс общего ключа

Чтобы получить новый случайный общий ключ, вызовите эту конечную точку с ResetSharedKey заданным значением true. Ниже приведен пример текста запроса:

{
  "resetSharedKey": true
}

Сброс ключа автоматически отключает двухфакторное требование для входа для пользователя, прошедшего проверку подлинности, до тех пор, пока он не будет включен более поздним запросом.

Забыли компьютер

Чтобы очистить cookie флаг "запомнить меня", если он присутствует, вызовите эту конечную точку с ForgetMachine заданным значением true. Ниже приведен пример текста запроса:

{
  "forgetMachine": true
}

Эта конечная точка не влияет на проверку подлинности на основе маркеров.

Использование конечной GET /manage/info точки

Получает адрес электронной почты и состояние подтверждения электронной почты пользователя, вошедшего в систему. Утверждения были опущены из этой конечной точки по соображениям безопасности. Если требуются утверждения, используйте интерфейсы API на стороне сервера, чтобы настроить конечную точку для утверждений. Или вместо предоставления общего доступа ко всем утверждениям пользователей предоставьте конечную точку проверки, которая принимает утверждение и отвечает, имеет ли пользователь его.

Запрос не требует каких-либо параметров. Текст ответа содержит Email свойства и IsEmailConfirmed свойства, как показано в следующем примере:

{
  "email": "string",
  "isEmailConfirmed": true
}

Использование конечной POST /manage/info точки

Обновляет адрес электронной почты и пароль пользователя, вошедшего в систему. Отправка NewEmail, NewPasswordа также OldPassword в тексте запроса, как показано в следующем примере:

{
  "newEmail": "string",
  "newPassword": "string",
  "oldPassword": "string"
}

Вот пример текста ответа:

{
  "email": "string",
  "isEmailConfirmed": false
}

См. также

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

Шаблоны ASP.NET Core предлагают проверку подлинности в одностраничных приложениях (SPAs), используя поддержку авторизации API. ASP.NET Core Identity для проверки подлинности и хранения пользователей объединяется с Duende Identity Server для реализации OpenID Connect.

Внимание

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

Параметр проверки подлинности был добавлен в шаблоны проектов Angular и React , аналогичные параметру проверки подлинности в шаблонах проектов веб-приложения (Model-View-Controller) (MVC) и веб-приложения (Razor Pages). Допустимые значения параметров — None и Individual. Шаблон проекта Reactjs и Redux в настоящее время не поддерживает параметр проверки подлинности.

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

Аутентификация пользователей и авторизация можно использовать как с angular, так и с spAs React. Откройте окно командной оболочки и выполните следующую команду:

Angular:

dotnet new angular -au Individual

React:

dotnet new react -au Individual

Предыдущая команда создает приложение ASP.NET Core с каталогом ClientApp , содержащим SPA.

Общее описание основных компонентов приложения ASP.NET

В следующих разделах описываются дополнения к проекту при включенной поддержке проверки подлинности:

Program.cs

В следующих примерах кода используется пакет NuGet Microsoft.AspNetCore.ApiAuthorization.IdentityServer . Примеры настройки проверки подлинности и авторизации API используют AddApiAuthorization методы расширения и AddIdentityServerJwt проверки подлинности. Проекты, использующие шаблоны проектов React или Angular SPA с проверкой подлинности, включают ссылку на этот пакет.

dotnet new angular -au Individual создает следующий Program.cs файл:

using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using output_directory_name.Data;
using output_directory_name.Models;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

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

builder.Services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

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

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

app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

Предыдущий код настраивает:

  • Identity с пользовательским интерфейсом по умолчанию:

    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlite(connectionString));
    builder.Services.AddDatabaseDeveloperPageExceptionFilter();
    
    builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    
  • IdentityServer с дополнительным AddApiAuthorization вспомогательным методом, который настраивает некоторые соглашения по умолчанию ASP.NET Core поверх IdentityServer:

    builder.Services.AddIdentityServer()
        .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
    
  • Проверка подлинности с помощью дополнительного вспомогательного метода AddIdentityServerJwt, который настраивает приложение для проверки маркеров JWT, созданных IdentityServer:

    builder.Services.AddAuthentication()
    .AddIdentityServerJwt();
    
  • ПО промежуточного слоя проверки подлинности, которое отвечает за проверку учетных данных запроса и настройку пользователя в контексте запроса:

    app.UseAuthentication();
    
  • ПО промежуточного слоя IdentityServer, которое предоставляет конечные точки OpenID Connect:

    app.UseIdentityServer();
    

Предупреждение

В этой статье показано использование строка подключения. С локальной базой данных пользователь не должен пройти проверку подлинности, но в рабочей среде строка подключения иногда включают пароль для проверки подлинности. Учетные данные владельца ресурса (ROPC) — это риск безопасности, который следует избежать в рабочих базах данных. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для приложений, развернутых в тестовых или рабочих средах, см. в разделе "Безопасные потоки проверки подлинности".

Служба приложений Azure в Linux

Для развертываний служб приложение Azure в Linux укажите издателя явным образом:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

В приведенном выше коде {AUTHORITY} заполнитель используется Authority при вызовах OpenID Connect.

Пример:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

Этот вспомогательный метод настраивает IdentityServer для использования поддерживаемой конфигурации. IdentityServer — это функциональная и расширяемая платформа для устранения проблем с безопасностью приложений. В то же время это обеспечивает ненужную сложность для наиболее распространенных сценариев. Следовательно, вам предоставляется набор соглашений и параметров конфигурации, которые считаются хорошей отправной точкой. После изменения проверки подлинности полная мощность IdentityServer по-прежнему доступна для настройки проверки подлинности в соответствии с вашими потребностями.

AddIdentityServerJwt

Этот вспомогательный метод настраивает схему политики для приложения в качестве обработчика проверки подлинности по умолчанию. Политика настроена, чтобы разрешить Identity обрабатывать все запросы, перенаправленные в любой Identity подпуть в пространстве URL-адресов "/Identity". JwtBearerHandler обрабатывает все остальные запросы. Кроме того, этот метод регистрирует <<ApplicationName>>API ресурс API в IdentityServer с областью <<ApplicationName>>API действия по умолчанию и настраивает ПО промежуточного слоя маркера носителя JWT для проверки маркеров, выданных IdentityServer для приложения.

WeatherForecastController

В файле обратите внимание на атрибут, [Authorize] примененный к классу, который указывает, что пользователю необходимо авторизоваться на основе политики по умолчанию для доступа к ресурсу. Политика авторизации по умолчанию настраивается для использования схемы проверки подлинности по умолчанию, которая настраивается AddIdentityServerJwt схемой политики, указанной выше, что делает JwtBearerHandler настроенный вспомогательным методом обработчик по умолчанию для запросов к приложению.

ApplicationDbContext

Обратите внимание, что в файле используется то же DbContext самое, за исключением того, что он расширяет ApiAuthorizationDbContext (более производный класс отIdentityDbContext) для включения схемы для IdentityServer.Identity

Чтобы получить полный контроль над схемой базы данных, наследуйте от одного из доступных IdentityDbContext классов и настройте контекст для включения Identity схемы путем вызова builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) OnModelCreating метода.

OidcConfigurationController

В файле обратите внимание на конечную точку, подготовленную для обслуживания параметров OIDC, которые клиент должен использовать.

appsettings.json

appsettings.json В файле корневого каталога проекта есть новый IdentityServer раздел, описывающий список настроенных клиентов. В следующем примере есть один клиент. Имя клиента соответствует имени приложения и сопоставляется по соглашению с параметром ClientId OAuth. Профиль указывает на настраиваемый тип приложения. Он используется внутри системы для управления соглашениями, упрощающими процесс настройки сервера. Существует несколько профилей, как описано в разделе "Профили приложений".

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

appsettings.Development.json В файле корневого каталога проекта есть IdentityServer раздел, описывающий ключ, используемый для подписывания маркеров. При развертывании в рабочей среде необходимо подготовить и развернуть ключ вместе с приложением, как описано в разделе "Развертывание в рабочей среде ".

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Общее описание приложения Angular

Поддержка проверки подлинности и авторизации API в шаблоне Angular находится в собственном модуле Angular в каталоге ClientApp/src/api-authorization . Модуль состоит из следующих элементов:

  • 3 компонента:
    • login.component.ts: обрабатывает поток входа приложения.
    • logout.component.ts: обрабатывает поток выхода приложения.
    • login-menu.component.ts: мини-приложение, отображающее один из следующих наборов ссылок:
      • Управление профилями пользователей и выход ссылок при проверке подлинности пользователя.
      • Регистрация и вход по ссылкам, когда пользователь не проходит проверку подлинности.
  • Защита AuthorizeGuard маршрута, которая может быть добавлена в маршруты и требует, чтобы пользователь прошел проверку подлинности перед посещением маршрута.
  • Перехватчик AuthorizeInterceptor HTTP, который подключает маркер доступа к исходящим HTTP-запросам, предназначенным для API при проверке подлинности пользователя.
  • Служба AuthorizeService , которая обрабатывает сведения о процессе проверки подлинности нижнего уровня и предоставляет сведения о пользователе, прошедшем rest проверку подлинности, приложению для потребления.
  • Модуль Angular, определяющий маршруты, связанные с частями проверки подлинности приложения. Он предоставляет компонент меню входа, перехватчик, защиту и службу для потребления из rest приложения.

Общее описание приложения React

Поддержка проверки подлинности и авторизации API в шаблоне React находится в каталоге ClientApp/src/components/api-authorization . Он состоит из следующих элементов:

  • 4 компонента:
    • Login.js: обрабатывает поток входа приложения.
    • Logout.js: обрабатывает поток выхода приложения.
    • LoginMenu.js: мини-приложение, отображающее один из следующих наборов ссылок:
      • Управление профилями пользователей и выход ссылок при проверке подлинности пользователя.
      • Регистрация и вход по ссылкам, когда пользователь не проходит проверку подлинности.
    • AuthorizeRoute.js: компонент маршрута, требующий проверки подлинности пользователя перед отрисовкой компонента, указанного в параметре Component .
  • Экспортированный authService экземпляр класса AuthorizeService , который обрабатывает сведения о процессе проверки подлинности более низкого уровня и предоставляет сведения о прошедшем проверку подлинности пользователей rest приложению для использования.

Теперь, когда вы видели основные компоненты решения, вы можете более подробно ознакомиться с отдельными сценариями для приложения.

Требовать авторизацию в новом API

По умолчанию система настроена для упрощения авторизации для новых API. Для этого создайте новый контроллер и добавьте [Authorize] атрибут в класс контроллера или в любое действие в контроллере.

Настройка обработчика проверки подлинности API

Чтобы настроить конфигурацию обработчика JWT API, настройте его JwtBearerOptions экземпляр:

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

Обработчик JWT API вызывает события, позволяющие управлять процессом проверки подлинности с помощью JwtBearerEvents. Чтобы обеспечить поддержку авторизации API, AddIdentityServerJwt регистрирует собственные обработчики событий.

Чтобы настроить обработку события, заключите существующий обработчик событий с дополнительной логикой по мере необходимости. Например:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

В приведенном выше коде OnTokenValidated обработчик событий заменяется пользовательской реализацией. Эта реализация:

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

Защита клиентского маршрута (Angular)

Защита клиентского маршрута выполняется путем добавления авторизации защиты в список гарантий, выполняемых при настройке маршрута. В качестве примера можно увидеть, как fetch-data маршрут настроен в модуле Main app Angular:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

Важно отметить, что защита маршрута не защищает фактическую конечную точку (которая по-прежнему требует [Authorize] применения к нему атрибута), но она запрещает пользователю переходить только к заданному клиентскому маршруту, если он не проходит проверку подлинности.

Проверка подлинности запросов API (Angular)

Проверка подлинности запросов к API, размещенным вместе с приложением, выполняется автоматически с помощью перехватчика HTTP-клиента, определенного приложением.

Защита клиентского маршрута (React)

Защита клиентского маршрута с помощью AuthorizeRoute компонента вместо обычного Route компонента. Например, обратите внимание, как fetch-data маршрут настроен в компоненте App :

<AuthorizeRoute path='/fetch-data' component={FetchData} />

Защита маршрута:

  • Не защищает фактическую конечную точку (которая по-прежнему требует применения атрибута [Authorize] к нему).
  • Только не позволяет пользователю переходить к заданному клиентскому маршруту, если он не проходит проверку подлинности.

Проверка подлинности запросов API (React)

Проверка подлинности запросов с помощью React выполняется путем импорта экземпляра authService из .AuthorizeService Маркер доступа извлекается из authService запроса и присоединен к запросу, как показано ниже. В компонентах React эта работа обычно выполняется в методе componentDidMount жизненного цикла или в результате некоторого взаимодействия с пользователем.

authService Импорт в компонент

import authService from './api-authorization/AuthorizeService'

Получение и присоединение маркера доступа к ответу

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

Развертывание в рабочей среде

Чтобы развернуть приложение в рабочей среде, необходимо подготовить следующие ресурсы:

  • База данных для хранения Identity учетных записей пользователей и грантов IdentityServer.
  • Рабочий сертификат, используемый для подписывания маркеров.
    • Для этого сертификата нет конкретных требований; это может быть самозаверяющий сертификат или сертификат, подготовленный центром сертификации.
    • Его можно создать с помощью стандартных инструментов, таких как PowerShell или OpenSSL.
    • Его можно установить в хранилище сертификатов на целевых компьютерах или развернуть в виде PFX-файла с надежным паролем.

Пример. Развертывание в поставщике веб-размещения, отличном от Azure

На панели веб-размещения создайте или загрузите сертификат. Затем в файле приложения appsettings.json измените IdentityServer раздел, чтобы включить сведения о ключе. Например:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

В предыдущем примере:

  • StoreName представляет имя хранилища сертификатов, в котором хранится сертификат. В этом случае он указывает на веб-хранилище размещения.
  • StoreLocation представляет место загрузки сертификата (CurrentUser в данном случае).
  • Name соответствует различаемой теме сертификата.

Пример. Развертывание в службе приложение Azure

В этом разделе описывается развертывание приложения в службе приложение Azure с помощью сертификата, хранящегося в хранилище сертификатов. Чтобы изменить приложение для загрузки сертификата из хранилища сертификатов, требуется план службы уровня "Стандартный" или лучше при настройке приложения в портал Azure на следующем шаге.

В файле приложения appsettings.json измените IdentityServer раздел, чтобы включить ключевые сведения:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • Имя хранилища представляет имя хранилища сертификатов, в котором хранится сертификат. В этом случае он указывает на личное хранилище пользователей.
  • Расположение хранилища представляет место загрузки сертификата из (CurrentUser или LocalMachine).
  • Свойство name в сертификате соответствует различаемой теме сертификата.

Чтобы развернуть службу приложение Azure, выполните действия, описанные в статье "Развертывание приложения в Azure", в котором объясняется, как создать необходимые ресурсы Azure и развернуть приложение в рабочей среде.

После выполнения предыдущих инструкций приложение развертывается в Azure, но еще не работает. Сертификат, используемый приложением, должен быть настроен в портал Azure. Найдите отпечаток сертификата и выполните действия, описанные в разделе "Загрузка сертификатов".

В то время как эти шаги упоминают SSL, в портал Azure есть раздел "Частные сертификаты", где можно отправить подготовленный сертификат для использования с приложением.

После настройки приложения и параметров приложения в портал Azure перезапустите приложение на портале.

Другие параметры конфигурации

Поддержка авторизации API строится на основе IdentityServer с набором соглашений, значений по умолчанию и усовершенствований, которые упрощают взаимодействие с spAs. Не нужно сказать, что полная мощность IdentityServer доступна за кулисами, если интеграция ASP.NET Core не охватывает ваш сценарий. Поддержка ASP.NET Core сосредоточена на приложениях", где все приложения создаются и развертываются нашей организацией. Таким образом, поддержка не предлагается для таких вещей, как согласие или федерация. Для этих сценариев используйте IdentityServer и следуйте их документации.

Профили приложений

Профили приложений — это предопределенные конфигурации для приложений, которые далее определяют их параметры. В настоящее время поддерживаются следующие профили:

  • IdentityServerSPA: представляет spa, размещенный вместе с IdentityServer в виде одной единицы.
    • Значение redirect_uri по умолчанию /authentication/login-callback.
    • Значение post_logout_redirect_uri по умолчанию /authentication/logout-callback.
    • Набор областей включает openidprofileи каждую область, определенную для API в приложении.
    • Набор разрешенных типов ответов OIDC или id_token token каждый из них по отдельности (id_token, token).
    • Допустимый режим ответа .fragment
  • SPA: представляет spa, который не размещается в IdentityServer.
    • Набор областей включает openidprofileи каждую область, определенную для API в приложении.
    • Набор разрешенных типов ответов OIDC или id_token token каждый из них по отдельности (id_token, token).
    • Допустимый режим ответа .fragment
  • IdentityServerJwt: представляет API, размещенный вместе с IdentityServer.
    • Приложение настроено на использование одной области, которая по умолчанию соответствует имени приложения.
  • API: представляет API, который не размещен в IdentityServer.
    • Приложение настроено на использование одной области, которая по умолчанию соответствует имени приложения.

Настройка с помощью AppSettings

Настройте приложения через систему конфигурации, добавив их в список Clients или Resources.

Настройте каждый клиент redirect_uri и post_logout_redirect_uri свойство, как показано в следующем примере:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

При настройке ресурсов можно настроить области для ресурса, как показано ниже:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

Настройка с помощью кода

Вы также можете настроить клиенты и ресурсы с помощью кода с помощью перегрузки AddApiAuthorization , которая принимает действие для настройки параметров.

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

Дополнительные ресурсы

Шаблоны ASP.NET Core 3.1 и более поздних версий предлагают проверку подлинности в одностраничных приложениях (SPAs) с помощью поддержки авторизации API. ASP.NET Core Identity для проверки подлинности и хранения пользователей объединяется с IdentityServer для реализации OpenID Connect.

Параметр проверки подлинности был добавлен в шаблоны проектов Angular и React , аналогичные параметру проверки подлинности в шаблонах проектов веб-приложения (Model-View-Controller) (MVC) и веб-приложения (Razor Pages). Допустимые значения параметров — None и Individual. Шаблон проекта Reactjs и Redux в настоящее время не поддерживает параметр проверки подлинности.

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

Аутентификация пользователей и авторизация можно использовать как с angular, так и с spAs React. Откройте окно командной оболочки и выполните следующую команду:

Angular:

dotnet new angular -o <output_directory_name> 

React:

dotnet new react -o <output_directory_name> -au Individual

Предыдущая команда создает приложение ASP.NET Core с каталогом ClientApp , содержащим SPA.

Общее описание основных компонентов приложения ASP.NET

В следующих разделах описываются дополнения к проекту при включенной поддержке проверки подлинности:

Класс Startup

В следующих примерах кода используется пакет NuGet Microsoft.AspNetCore.ApiAuthorization.IdentityServer . Примеры настройки проверки подлинности и авторизации API используют AddApiAuthorization методы расширения и AddIdentityServerJwt проверки подлинности. Проекты, использующие шаблоны проектов React или Angular SPA с проверкой подлинности, включают ссылку на этот пакет.

Класс Startup имеет следующие дополнения:

  • Startup.ConfigureServices Внутри метода:

    • Identity с пользовательским интерфейсом по умолчанию:

      services.AddDbContext<ApplicationDbContext>(options =>
          options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
      
      services.AddDefaultIdentity<ApplicationUser>()
          .AddEntityFrameworkStores<ApplicationDbContext>();
      
    • IdentityServer с дополнительным AddApiAuthorization вспомогательным методом, который настраивает некоторые соглашения по умолчанию ASP.NET Core поверх IdentityServer:

      services.AddIdentityServer()
          .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
      
    • Проверка подлинности с помощью дополнительного вспомогательного метода AddIdentityServerJwt, который настраивает приложение для проверки маркеров JWT, созданных IdentityServer:

      services.AddAuthentication()
          .AddIdentityServerJwt();
      
  • Startup.Configure Внутри метода:

    • ПО промежуточного слоя проверки подлинности, которое отвечает за проверку учетных данных запроса и настройку пользователя в контексте запроса:

      app.UseAuthentication();
      
    • ПО промежуточного слоя IdentityServer, которое предоставляет конечные точки OpenID Connect:

      app.UseIdentityServer();
      

Предупреждение

В этой статье показано использование строка подключения. С локальной базой данных пользователь не должен пройти проверку подлинности, но в рабочей среде строка подключения иногда включают пароль для проверки подлинности. Учетные данные владельца ресурса (ROPC) — это риск безопасности, который следует избежать в рабочих базах данных. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для приложений, развернутых в тестовых или рабочих средах, см. в разделе "Безопасные потоки проверки подлинности".

Служба приложений Azure в Linux

Для развертываний служб приложение Azure в Linux укажите издателя явно вStartup.ConfigureServices:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

В приведенном выше коде {AUTHORITY} заполнитель используется Authority при вызовах OpenID Connect.

Пример:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

Этот вспомогательный метод настраивает IdentityServer для использования поддерживаемой конфигурации. IdentityServer — это функциональная и расширяемая платформа для устранения проблем с безопасностью приложений. В то же время это обеспечивает ненужную сложность для наиболее распространенных сценариев. Следовательно, вам предоставляется набор соглашений и параметров конфигурации, которые считаются хорошей отправной точкой. После изменения проверки подлинности полная мощность IdentityServer по-прежнему доступна для настройки проверки подлинности в соответствии с вашими потребностями.

AddIdentityServerJwt

Этот вспомогательный метод настраивает схему политики для приложения в качестве обработчика проверки подлинности по умолчанию. Политика настроена, чтобы разрешить Identity обрабатывать все запросы, перенаправленные в любой Identity подпуть в пространстве URL-адресов "/Identity". JwtBearerHandler обрабатывает все остальные запросы. Кроме того, этот метод регистрирует <<ApplicationName>>API ресурс API в IdentityServer с областью <<ApplicationName>>API действия по умолчанию и настраивает ПО промежуточного слоя маркера носителя JWT для проверки маркеров, выданных IdentityServer для приложения.

WeatherForecastController

В файле обратите внимание на атрибут, [Authorize] примененный к классу, который указывает, что пользователю необходимо авторизоваться на основе политики по умолчанию для доступа к ресурсу. Политика авторизации по умолчанию настраивается для использования схемы проверки подлинности по умолчанию, которая настраивается AddIdentityServerJwt схемой политики, указанной выше, что делает JwtBearerHandler настроенный вспомогательным методом обработчик по умолчанию для запросов к приложению.

ApplicationDbContext

Обратите внимание, что в файле используется то же DbContext самое, за исключением того, что он расширяет ApiAuthorizationDbContext (более производный класс отIdentityDbContext) для включения схемы для IdentityServer.Identity

Чтобы получить полный контроль над схемой базы данных, наследуйте от одного из доступных IdentityDbContext классов и настройте контекст для включения Identity схемы путем вызова builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) OnModelCreating метода.

OidcConfigurationController

В файле обратите внимание на конечную точку, подготовленную для обслуживания параметров OIDC, которые клиент должен использовать.

appsettings.json

appsettings.json В файле корневого каталога проекта есть новый IdentityServer раздел, описывающий список настроенных клиентов. В следующем примере есть один клиент. Имя клиента соответствует имени приложения и сопоставляется по соглашению с параметром ClientId OAuth. Профиль указывает на настраиваемый тип приложения. Он используется внутри системы для управления соглашениями, упрощающими процесс настройки сервера. Существует несколько профилей, как описано в разделе "Профили приложений".

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

appsettings.Development.json В файле корневого каталога проекта есть IdentityServer раздел, описывающий ключ, используемый для подписывания маркеров. При развертывании в рабочей среде необходимо подготовить и развернуть ключ вместе с приложением, как описано в разделе "Развертывание в рабочей среде ".

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Общее описание приложения Angular

Поддержка проверки подлинности и авторизации API в шаблоне Angular находится в собственном модуле Angular в каталоге ClientApp/src/api-authorization . Модуль состоит из следующих элементов:

  • 3 компонента:
    • login.component.ts: обрабатывает поток входа приложения.
    • logout.component.ts: обрабатывает поток выхода приложения.
    • login-menu.component.ts: мини-приложение, отображающее один из следующих наборов ссылок:
      • Управление профилями пользователей и выход ссылок при проверке подлинности пользователя.
      • Регистрация и вход по ссылкам, когда пользователь не проходит проверку подлинности.
  • Защита AuthorizeGuard маршрута, которая может быть добавлена в маршруты и требует, чтобы пользователь прошел проверку подлинности перед посещением маршрута.
  • Перехватчик AuthorizeInterceptor HTTP, который подключает маркер доступа к исходящим HTTP-запросам, предназначенным для API при проверке подлинности пользователя.
  • Служба AuthorizeService , которая обрабатывает сведения о процессе проверки подлинности нижнего уровня и предоставляет сведения о пользователе, прошедшем rest проверку подлинности, приложению для потребления.
  • Модуль Angular, определяющий маршруты, связанные с частями проверки подлинности приложения. Он предоставляет компонент меню входа, перехватчик, защиту и службу для потребления из rest приложения.

Общее описание приложения React

Поддержка проверки подлинности и авторизации API в шаблоне React находится в каталоге ClientApp/src/components/api-authorization . Он состоит из следующих элементов:

  • 4 компонента:
    • Login.js: обрабатывает поток входа приложения.
    • Logout.js: обрабатывает поток выхода приложения.
    • LoginMenu.js: мини-приложение, отображающее один из следующих наборов ссылок:
      • Управление профилями пользователей и выход ссылок при проверке подлинности пользователя.
      • Регистрация и вход по ссылкам, когда пользователь не проходит проверку подлинности.
    • AuthorizeRoute.js: компонент маршрута, требующий проверки подлинности пользователя перед отрисовкой компонента, указанного в параметре Component .
  • Экспортированный authService экземпляр класса AuthorizeService , который обрабатывает сведения о процессе проверки подлинности более низкого уровня и предоставляет сведения о прошедшем проверку подлинности пользователей rest приложению для использования.

Теперь, когда вы видели основные компоненты решения, вы можете более подробно ознакомиться с отдельными сценариями для приложения.

Требовать авторизацию в новом API

По умолчанию система настроена для упрощения авторизации для новых API. Для этого создайте новый контроллер и добавьте [Authorize] атрибут в класс контроллера или в любое действие в контроллере.

Настройка обработчика проверки подлинности API

Чтобы настроить конфигурацию обработчика JWT API, настройте его JwtBearerOptions экземпляр:

services.AddAuthentication()
    .AddIdentityServerJwt();

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

Обработчик JWT API вызывает события, позволяющие управлять процессом проверки подлинности с помощью JwtBearerEvents. Чтобы обеспечить поддержку авторизации API, AddIdentityServerJwt регистрирует собственные обработчики событий.

Чтобы настроить обработку события, заключите существующий обработчик событий с дополнительной логикой по мере необходимости. Например:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

В приведенном выше коде OnTokenValidated обработчик событий заменяется пользовательской реализацией. Эта реализация:

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

Защита клиентского маршрута (Angular)

Защита клиентского маршрута выполняется путем добавления авторизации защиты в список гарантий, выполняемых при настройке маршрута. В качестве примера можно увидеть, как fetch-data маршрут настроен в модуле Main app Angular:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

Важно отметить, что защита маршрута не защищает фактическую конечную точку (которая по-прежнему требует [Authorize] применения к нему атрибута), но она запрещает пользователю переходить только к заданному клиентскому маршруту, если он не проходит проверку подлинности.

Проверка подлинности запросов API (Angular)

Проверка подлинности запросов к API, размещенным вместе с приложением, выполняется автоматически с помощью перехватчика HTTP-клиента, определенного приложением.

Защита клиентского маршрута (React)

Защита клиентского маршрута с помощью AuthorizeRoute компонента вместо обычного Route компонента. Например, обратите внимание, как fetch-data маршрут настроен в компоненте App :

<AuthorizeRoute path='/fetch-data' component={FetchData} />

Защита маршрута:

  • Не защищает фактическую конечную точку (которая по-прежнему требует применения атрибута [Authorize] к нему).
  • Только не позволяет пользователю переходить к заданному клиентскому маршруту, если он не проходит проверку подлинности.

Проверка подлинности запросов API (React)

Проверка подлинности запросов с помощью React выполняется путем импорта экземпляра authService из .AuthorizeService Маркер доступа извлекается из authService запроса и присоединен к запросу, как показано ниже. В компонентах React эта работа обычно выполняется в методе componentDidMount жизненного цикла или в результате некоторого взаимодействия с пользователем.

authService Импорт в компонент

import authService from './api-authorization/AuthorizeService'

Получение и присоединение маркера доступа к ответу

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

Развертывание в рабочей среде

Чтобы развернуть приложение в рабочей среде, необходимо подготовить следующие ресурсы:

  • База данных для хранения Identity учетных записей пользователей и грантов IdentityServer.
  • Рабочий сертификат, используемый для подписывания маркеров.
    • Для этого сертификата нет конкретных требований; это может быть самозаверяющий сертификат или сертификат, подготовленный центром сертификации.
    • Его можно создать с помощью стандартных инструментов, таких как PowerShell или OpenSSL.
    • Его можно установить в хранилище сертификатов на целевых компьютерах или развернуть в виде PFX-файла с надежным паролем.

Пример. Развертывание в поставщике веб-размещения, отличном от Azure

На панели веб-размещения создайте или загрузите сертификат. Затем в файле приложения appsettings.json измените IdentityServer раздел, чтобы включить сведения о ключе. Например:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

В предыдущем примере:

  • StoreName представляет имя хранилища сертификатов, в котором хранится сертификат. В этом случае он указывает на веб-хранилище размещения.
  • StoreLocation представляет место загрузки сертификата (CurrentUser в данном случае).
  • Name соответствует различаемой теме сертификата.

Пример. Развертывание в службе приложение Azure

В этом разделе описывается развертывание приложения в службе приложение Azure с помощью сертификата, хранящегося в хранилище сертификатов. Чтобы изменить приложение для загрузки сертификата из хранилища сертификатов, требуется план службы уровня "Стандартный" или лучше при настройке приложения в портал Azure на следующем шаге.

В файле приложения appsettings.json измените IdentityServer раздел, чтобы включить ключевые сведения:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • Имя хранилища представляет имя хранилища сертификатов, в котором хранится сертификат. В этом случае он указывает на личное хранилище пользователей.
  • Расположение хранилища представляет место загрузки сертификата из (CurrentUser или LocalMachine).
  • Свойство name в сертификате соответствует различаемой теме сертификата.

Чтобы развернуть службу приложение Azure, выполните действия, описанные в статье "Развертывание приложения в Azure", в котором объясняется, как создать необходимые ресурсы Azure и развернуть приложение в рабочей среде.

После выполнения предыдущих инструкций приложение развертывается в Azure, но еще не работает. Сертификат, используемый приложением, должен быть настроен в портал Azure. Найдите отпечаток сертификата и выполните действия, описанные в разделе "Загрузка сертификатов".

В то время как эти шаги упоминают SSL, в портал Azure есть раздел "Частные сертификаты", где можно отправить подготовленный сертификат для использования с приложением.

После настройки приложения и параметров приложения в портал Azure перезапустите приложение на портале.

Другие параметры конфигурации

Поддержка авторизации API строится на основе IdentityServer с набором соглашений, значений по умолчанию и усовершенствований, которые упрощают взаимодействие с spAs. Не нужно сказать, что полная мощность IdentityServer доступна за кулисами, если интеграция ASP.NET Core не охватывает ваш сценарий. Поддержка ASP.NET Core сосредоточена на приложениях", где все приложения создаются и развертываются нашей организацией. Таким образом, поддержка не предлагается для таких вещей, как согласие или федерация. Для этих сценариев используйте IdentityServer и следуйте их документации.

Профили приложений

Профили приложений — это предопределенные конфигурации для приложений, которые далее определяют их параметры. В настоящее время поддерживаются следующие профили:

  • IdentityServerSPA: представляет spa, размещенный вместе с IdentityServer в виде одной единицы.
    • Значение redirect_uri по умолчанию /authentication/login-callback.
    • Значение post_logout_redirect_uri по умолчанию /authentication/logout-callback.
    • Набор областей включает openidprofileи каждую область, определенную для API в приложении.
    • Набор разрешенных типов ответов OIDC или id_token token каждый из них по отдельности (id_token, token).
    • Допустимый режим ответа .fragment
  • SPA: представляет spa, который не размещается в IdentityServer.
    • Набор областей включает openidprofileи каждую область, определенную для API в приложении.
    • Набор разрешенных типов ответов OIDC или id_token token каждый из них по отдельности (id_token, token).
    • Допустимый режим ответа .fragment
  • IdentityServerJwt: представляет API, размещенный вместе с IdentityServer.
    • Приложение настроено на использование одной области, которая по умолчанию соответствует имени приложения.
  • API: представляет API, который не размещен в IdentityServer.
    • Приложение настроено на использование одной области, которая по умолчанию соответствует имени приложения.

Настройка с помощью AppSettings

Настройте приложения через систему конфигурации, добавив их в список Clients или Resources.

Настройте каждый клиент redirect_uri и post_logout_redirect_uri свойство, как показано в следующем примере:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

При настройке ресурсов можно настроить области для ресурса, как показано ниже:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

Настройка с помощью кода

Вы также можете настроить клиенты и ресурсы с помощью кода с помощью перегрузки AddApiAuthorization , которая принимает действие для настройки параметров.

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

Дополнительные ресурсы