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


Защищенный веб-API: проверка областей и ролей приложения

В этой статье описывается, как можно добавить авторизацию в веб-API. Эта защита гарантирует, что API будет вызываться только:

  • приложениями от имени пользователей с нужными областями и ролями;
  • управляющими приложениями, имеющими правильные роли приложений.

Фрагменты кода в этой статье взяты из следующих примеров кода на сайте GitHub:

Чтобы защитить веб-API ASP.NET или ASP.NET Core, необходимо добавить атрибут [Authorize] в один из следующих элементов:

  • сам контроллер, если требуется защитить все действия контроллера;
  • действие отдельного контроллера для API.
    [Authorize]
    public class TodoListController : Controller
    {
     // ...
    }

Но этой защиты недостаточно. Она гарантирует только то, что ASP.NET и ASP.NET Core проверят маркер. API необходимо проверить, что маркер, используемый для вызова API, запрашивается с ожидаемыми утверждениями. В частности, требуют проверки следующие утверждения.

  • Области, если API вызывается от имени пользователя.
  • Роли приложения, если API можно вызывать из управляющего приложения.

Проверка областей в интерфейсах API, вызываемых от имени пользователей

Если клиентское приложение вызывает API от имени пользователя, API должен запросить токен носителя с конкретными областями для API. Дополнительные сведения см. в Конфигурация кода | Токен носителя.

В ASP.NET Core можно использовать Microsoft.Identity.Web для проверки областей в каждом действии контроллера. Вы также можете проверять их на уровне отдельного контроллера или приложения в целом.

Проверка областей для каждого действия контроллера

Чтобы проверить области для действия контроллера, используйте атрибут [RequiredScope]. Этот атрибут поддерживает несколько переопределений. Одно из них напрямую принимает требуемые области, а другое принимает ключ конфигурации.

Проверка областей для действия контроллера с жестко заданными областями

В следующем фрагменте кода показано использование атрибута [RequiredScope] с жестко заданными областями.

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : Controller
{
    /// <summary>
    /// The web API will accept only tokens that have the `access_as_user` scope for
    /// this API.
    /// </summary>
    const string scopeRequiredByApi = "access_as_user";

    // GET: api/values
    [HttpGet]
    [RequiredScope(scopeRequiredByApi)]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}
Проверка областей для действия контроллера с определением областей в конфигурации

Вы также можете объявить требуемые области в конфигурации и передать ссылку на ключ этой конфигурации:

Например, если в appsettings.json у вас есть следующая конфигурация:

{
 "AzureAd" : {
   // more settings
   "Scopes" : "access_as_user access_as_admin"
  }
}

В этом случае ссылка на область в атрибуте [RequiredScope] будет выглядеть так:

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : Controller
{
    // GET: api/values
    [HttpGet]
    [RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}
Проверка областей с условием

В некоторых случаях вам нужна условная проверка областей. Для нее можно применить метод расширения VerifyUserHasAnyAcceptedScope для HttpContext.

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : Controller
{
    /// <summary>
    /// The web API will accept only tokens 1) for users, 2) that have the `access_as_user` scope for
    /// this API.
    /// </summary>
    static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };

    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
         HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
        // Do the work and return the result.
        // ...
    }
 // ...
}

Проверка областей на уровне контроллера

Вы также можете проверять области для всего контроллера.

Проверка области для контроллера с жестко заданными областями

В следующем фрагменте кода показано использование атрибута [RequiredScope] с жестко заданными областями для контроллера. Чтобы использовать RequiredScopeAttribute, необходимо выполнить следующие действия:

  • Использование AddMicrosoftIdentityWebApi в Startup.cs, как показано в конфигурации кода
  • или в противном случае добавьте ScopeAuthorizationRequirement политики авторизации, как описано в политиках авторизации.
using Microsoft.Identity.Web

[Authorize]
[RequiredScope(scopeRequiredByApi)]
public class TodoListController : Controller
{
    /// <summary>
    /// The web API will accept only tokens 1) for users, 2) that have the `access_as_user` scope for
    /// this API.
    /// </summary>
    static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };

    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}
Проверка областей для контроллера с определением областей в конфигурации

Как и для действия, вы можете объявить требуемые области в конфигурации и передать ссылку на ключ этой конфигурации:

using Microsoft.Identity.Web

[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : Controller
{
    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}

Проверка областей на глобальном уровне

Мы рекомендуем детально определить области действия для веб-API и проверить эти области для каждого действия контроллера. Но вы можете проверить области на уровне приложения или контроллера. Дополнительные сведения см . в документации по ASP.NET Core на основе утверждений.

Что входит в проверку?

Атрибут [RequiredScope] и метод VerifyUserHasAnyAcceptedScope выполняют примерно следующие шаги:

  • Проверьте, существует ли утверждение с именем http://schemas.microsoft.com/identity/claims/scope или scp.
  • Проверьте, что утверждение имеет значение, которое содержит область, ожидаемую API.

Проверка ролей приложения в интерфейсах API, которые вызываются приложениями управляющей программы

Если веб-API вызывается приложением управляющей программы, это приложение должно требовать разрешения приложения для веб-API. Как показано в разделе Предоставление разрешений приложения (роли приложений), API предоставляет такие разрешения. Одним из примеров является роль приложения access_as_application.

Теперь необходимо, чтобы ваш API проверял, что полученный маркер содержит утверждение roles и что это утверждение имеет ожидаемое значение. Код проверки аналогичен коду, который проверяет делегированные разрешения, за исключением того, что действие контроллера проверяет роли, а не области.

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

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : ApiController
{
    public IEnumerable<TodoItem> Get()
    {
        HttpContext.ValidateAppRole("access_as_application");
        // ...
    }

Вместо этого можно использовать [Authorize(Roles = "access_as_application")] атрибуты на контроллере или действии (или на странице razor).

[Authorize(Roles = "access_as_application")]
MyController : ApiController
{
    // ...
}

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

Рабочие примеры см. в пошаговом руководстве по созданию веб-приложения с авторизацией по ролям и группам.

Проверка ролей приложений в интерфейсах API, вызываемых от имени пользователей

Пользователи также могут использовать утверждения ролей в шаблонах назначения пользователей, как показано в разделе Практическое руководство. Добавление ролей приложения в приложение и их получение в токене. Если роли могут быть назначены обоим, проверка ролей позволит приложениям входить в систему в качестве пользователей, а пользователям входить в качестве приложений. Для предотвращения этой путаницы рекомендуется объявлять разные роли для пользователей и приложений.

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

Принятие маркеров только для приложений, если веб-API должен вызываться только управляющими приложениями

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

string oid = ClaimsPrincipal.Current.FindFirst("oid")?.Value;
string sub = ClaimsPrincipal.Current.FindFirst("sub")?.Value;
bool isAppOnly = oid != null && sub != null && oid == sub;

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

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

Вместо авторизации на основе ролей приложения можно использовать для защиты веб-API другой шаблон авторизации, основанный на списках управления доступом (ACL), который позволяет управлять маркерами без утверждения roles.

Если вы используете Microsoft.Identity.Web в ASP.NET Core, необходимо объявить, что вы используете авторизацию на основе ACL, в противном случае Microsoft Identity Web создает исключение, если ни роли, ни области не указаны в утверждениях:

System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token.

Чтобы избежать этого исключения, задайте AllowWebApiToBeAuthorizedByACL для свойства конфигурации значение trueappsettings.json или программно.

{
 "AzureAD"
 {
  // other properties
  "AllowWebApiToBeAuthorizedByACL" : true,
  // other properties
 }
}

Если задано значение AllowWebApiToBeAuthorizedByACLtrue, это ваша ответственность за обеспечение механизма ACL.

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

  • Узнайте больше, создав веб-приложение ASP.NET Core, которое входит в систему пользователей в следующей серии учебников с несколькими частью

  • Ознакомьтесь с примерами веб-API платформа удостоверений Майкрософт