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


Как использовать Identity для защиты серверной части веб-API для SPA

Примечание.

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

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

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

Внимание

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

В текущем выпуске смотрите версию статьи для .NET 9.

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

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

Предварительные требования

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

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

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

Установка пакетов 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-основанная проверка подлинности безопасно встроена в браузер и "просто работает".

Тестирование с помощью клиентов, которые не являются браузерами

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

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

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

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

    request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);
    

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

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

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

Маркеры не являются стандартными JSON Web Tokens (JWTs). Использование пользовательских значков намеренно, так как встроенный Identity API в основном предназначен для простых сценариев. Параметр токена не предназначен для полноценного поставщика услуг идентификации или сервера токенов, а вместо этого служит альтернативой варианту 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 обязательны. Если включена двухфакторная проверка подлинности (2FA), требуется либо TwoFactorCode, либо TwoFactorRecoveryCode. Если 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 предоставляет текст по умолчанию для других сообщений электронной почты, которые необходимо отправить, например, для двухфакторной аутентификации и сброса пароля. Чтобы настроить эти сообщения электронной почты, предоставьте пользовательскую реализацию 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. Коды восстановления используются для входа, если приложение для аутентификации недоступно. Пример текста ответа после успешного включения 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"
}

Если у пользователя нет доступа к приложению аутентификатор, войдите в систему, вызвав /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. Шаблон проекта React.js и Redux не поддерживает параметр аутентификации на данный момент.

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

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

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();
    

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

В этой статье показано использование строк подключения. С локальной базой данных пользователю не нужно проходить проверку подлинности, но в production-среде строка подключения иногда включает пароль для проверки подлинности. Учетные данные владельца ресурса (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 Bearer для проверки токенов, выданных IdentityServer для приложения.

WeatherForecastController

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

ApplicationDbContext

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

Чтобы получить полный контроль над схемой базы данных, наследуйте от одного из доступных 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, которая обрабатывает детали процесса аутентификации на более низком уровне и предоставляет информацию о пользователе, прошедшем проверку подлинности, для использования остальной частью приложения.
  • Модуль Angular, определяющий маршруты, связанные с частями проверки подлинности приложения. Он предоставляет компонент меню входа, перехватчик, защиту и сервис для использования остальной частью приложения.

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

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

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

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

Требовать авторизацию в новом 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 конфигурирован в модуле 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).
  • Свойство имени в сертификате соответствует выделенному субъекту сертификата.

Чтобы развернуть службу приложение 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. Шаблон проекта React.js и Redux не поддерживает параметр аутентификации на данный момент.

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

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

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();
      

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

В этой статье показано использование строк подключения. С локальной базой данных пользователю не нужно проходить проверку подлинности, но в production-среде строка подключения иногда включает пароль для проверки подлинности. Учетные данные владельца ресурса (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 Bearer для проверки токенов, выданных IdentityServer для приложения.

WeatherForecastController

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

ApplicationDbContext

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

Чтобы получить полный контроль над схемой базы данных, наследуйте по одному из доступных 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, которая обрабатывает детали процесса аутентификации на более низком уровне и предоставляет информацию о пользователе, прошедшем проверку подлинности, для использования остальной частью приложения.
  • Модуль Angular, определяющий маршруты, связанные с частями проверки подлинности приложения. Он предоставляет компонент меню входа, перехватчик, защиту и сервис для использования остальной частью приложения.

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

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

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

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

Требовать авторизацию в новом 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 конфигурирован в модуле 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).
  • Свойство имени в сертификате соответствует выделенному субъекту сертификата.

Чтобы развернуть службу приложение 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"));
});

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