Защищенный веб-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.

Если вы используете ASP.NET Core, необходимо объявить, что вы используете Microsoft.Identity.Web авторизацию на основе 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 платформа удостоверений Майкрософт