Защищенный веб-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
на значение true
в appsettings.json или программно.
{
"AzureAD"
{
// other properties
"AllowWebApiToBeAuthorizedByACL" : true,
// other properties
}
}
Если задано значение AllowWebApiToBeAuthorizedByACL
true
, это ваша ответственность за обеспечение механизма ACL.