Chroniony internetowy interfejs API: weryfikowanie zakresów i ról aplikacji

W tym artykule opisano sposób dodawania autoryzacji do internetowego interfejsu API. Ta ochrona gwarantuje, że interfejs API jest wywoływany tylko przez:

  • Aplikacje w imieniu użytkowników, którzy mają odpowiednie zakresy i role.
  • Aplikacje demona, które mają odpowiednie role aplikacji.

Fragmenty kodu w tym artykule są wyodrębniane z następujących przykładów kodu w usłudze GitHub:

Aby chronić interfejs API sieci Web ASP.NET lub ASP.NET Core, należy dodać [Authorize] atrybut do jednego z następujących elementów:

  • Kontroler ma być chroniony, jeśli chcesz, aby wszystkie akcje kontrolera było chronione
  • Akcja pojedynczego kontrolera dla interfejsu API
    [Authorize]
    public class TodoListController : Controller
    {
     // ...
    }

Ale ta ochrona nie wystarczy. Gwarantuje to tylko, że ASP.NET i ASP.NET Core weryfikują token. Interfejs API musi sprawdzić, czy token używany do wywoływania interfejsu API jest żądany z oczekiwanymi oświadczeniami. Te oświadczenia wymagają w szczególności weryfikacji:

  • Zakresy , jeśli interfejs API jest wywoływany w imieniu użytkownika.
  • Role aplikacji, jeśli interfejs API można wywołać z aplikacji demona.

Weryfikowanie zakresów w interfejsach API wywoływanych w imieniu użytkowników

Jeśli aplikacja kliencka wywołuje interfejs API w imieniu użytkownika, interfejs API musi zażądać tokenu elementu nośnego, który ma określone zakresy dla interfejsu API. Aby uzyskać więcej informacji, zobacz Konfiguracja kodu | Token elementu nośnego.

W ASP.NET Core można użyć microsoft.Identity.Web , aby zweryfikować zakresy w każdej akcji kontrolera. Można je również zweryfikować na poziomie kontrolera lub dla całej aplikacji.

Weryfikowanie zakresów w każdej akcji kontrolera

Zakresy w akcji kontrolera można sprawdzić przy użyciu atrybutu [RequiredScope] . Ten atrybut ma kilka przesłonięć. Jeden, który pobiera wymagane zakresy bezpośrednio, i taki, który pobiera klucz do konfiguracji.

Weryfikowanie zakresów w akcji kontrolera z zakodowanymi na stałe zakresami

Poniższy fragment kodu przedstawia użycie atrybutu [RequiredScope] z zakodowanymi na stałe zakresami.

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.
        // ...
    }
 // ...
}
Weryfikowanie zakresów w akcji kontrolera z zakresami zdefiniowanymi w konfiguracji

Możesz również zadeklarować te wymagane zakresy w konfiguracji i odwołać się do klucza konfiguracji:

Jeśli na przykład w appsettings.json masz następującą konfigurację:

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

Następnie odwołaj się do niego w atrybucie [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.
        // ...
    }
 // ...
}
Warunkowe weryfikowanie zakresów

Istnieją przypadki, w których chcesz warunkowo zweryfikować zakresy. Można to zrobić przy użyciu VerifyUserHasAnyAcceptedScope metody rozszerzenia w pliku 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.
        // ...
    }
 // ...
}

Weryfikowanie zakresów na poziomie kontrolera

Można również sprawdzić zakresy dla całego kontrolera

Weryfikowanie zakresów na kontrolerze z zakodowanymi na stałe zakresami

Poniższy fragment kodu przedstawia użycie atrybutu [RequiredScope] z zakodowanymi na stałe zakresami na kontrolerze. Aby użyć atrybutu RequiredScopeAttribute, musisz wykonać jedną z następujących czynności:

  • Użyj AddMicrosoftIdentityWebApi w Startup.cs, jak pokazano w konfiguracji kodu
  • lub w inny sposób dodaj element ScopeAuthorizationRequirement do zasad autoryzacji zgodnie z wyjaśnieniem w zasadach autoryzacji.
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.
        // ...
    }
 // ...
}
Weryfikowanie zakresów na kontrolerze z zakresami zdefiniowanymi w konfiguracji

Podobnie jak w przypadku akcji, możesz również zadeklarować te wymagane zakresy w konfiguracji i odwołać się do klucza konfiguracji:

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.
        // ...
    }
 // ...
}

Weryfikowanie zakresów bardziej globalnie

Definiowanie szczegółowych zakresów internetowego interfejsu API i weryfikowanie zakresów w każdej akcji kontrolera jest zalecane. Można jednak również zweryfikować zakresy na poziomie aplikacji lub kontrolera. Aby uzyskać szczegółowe informacje, zobacz autoryzację opartą na oświadczeniach w dokumentacji ASP.NET Core.

Co zostało zweryfikowane?

Atrybut [RequiredScope] i VerifyUserHasAnyAcceptedScope metoda działają podobnie do następujących kroków:

  • Sprawdź, czy istnieje oświadczenie o nazwie http://schemas.microsoft.com/identity/claims/scope lub scp.
  • Sprawdź, czy oświadczenie ma wartość zawierającą zakres oczekiwany przez interfejs API.

Weryfikowanie ról aplikacji w interfejsach API wywoływanych przez aplikacje demona

Jeśli internetowy interfejs API jest wywoływany przez aplikację demona, ta aplikacja powinna wymagać uprawnień aplikacji do internetowego interfejsu API. Jak pokazano w temacie Uwidacznianie uprawnień aplikacji (role aplikacji), interfejs API uwidacznia takie uprawnienia. Przykładem jest access_as_application rola aplikacji.

Teraz musisz sprawdzić, czy otrzymany token zawiera roles oświadczenie i czy to oświadczenie ma oczekiwaną wartość. Kod weryfikacyjny jest podobny do kodu, który weryfikuje delegowane uprawnienia, z tą różnicą, że kontroler wykonuje testy akcji dla ról zamiast zakresów:

Poniższy fragment kodu pokazuje, jak zweryfikować rolę aplikacji;

using Microsoft.Identity.Web

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

Zamiast tego można użyć [Authorize(Roles = "access_as_application")] atrybutów na kontrolerze lub akcji (lub strony razor).

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

Autoryzacja oparta na rolach w programie ASP.NET Core zawiera kilka metod implementowania autoryzacji opartej na rolach. Deweloperzy mogą wybrać jedną z nich, która odpowiada odpowiednim scenariuszom.

Aby zapoznać się z przykładami roboczymi, zobacz samouczek przyrostowy aplikacji internetowej dotyczący autoryzacji według ról i grup.

Weryfikowanie ról aplikacji w interfejsach API wywoływanych w imieniu użytkowników

Użytkownicy mogą również używać oświadczeń ról we wzorcach przypisań użytkowników, jak pokazano w temacie Jak dodać role aplikacji w aplikacji i odbierać je w tokenie. Jeśli role są przypisywane do obu tych ról, sprawdzanie ról pozwoli aplikacjom logować się jako użytkownicy i użytkownicy logują się jako aplikacje. Zalecamy zadeklarowanie różnych ról dla użytkowników i aplikacji, aby zapobiec tym nieporozumieniom.

Jeśli zdefiniowano role aplikacji z użytkownikiem/grupą, oświadczenie ról można również zweryfikować w interfejsie API wraz z zakresami. Logika weryfikacji ról aplikacji w tym scenariuszu pozostaje taka sama jak w przypadku, gdy interfejs API jest wywoływany przez aplikacje demona, ponieważ nie ma różnicy w oświadczeniach roli dla użytkownika/grupy i aplikacji.

Akceptowanie tokenów tylko dla aplikacji, jeśli internetowy interfejs API powinien być wywoływany tylko przez aplikacje demona

Jeśli chcesz, aby tylko aplikacje demona wywoływać internetowy interfejs API, dodaj warunek, że token jest tokenem tylko dla aplikacji podczas walidacji roli aplikacji.

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

Sprawdzenie warunku odwrotnego umożliwia wywoływanie interfejsu API tylko aplikacjom, które logują się do użytkownika.

Używanie autoryzacji opartej na listach ACL

Alternatywnie w przypadku autoryzacji opartej na rolach aplikacji można chronić internetowy interfejs API za pomocą wzorca autoryzacji opartego na liście kontroli dostępu (ACL) w celu kontrolowania tokenów bez roles oświadczenia.

Jeśli korzystasz z Microsoft.Identity.Web usługi ASP.NET Core, musisz zadeklarować, że używasz autoryzacji opartej na liście ACL. W przeciwnym razie witryna Microsoft Identity Web zgłosi wyjątek, jeśli ani role, ani zakresy nie znajdują się w podanych oświadczeniach:

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

Aby uniknąć tego wyjątku, ustaw AllowWebApiToBeAuthorizedByACL właściwość konfiguracji na true w appsettings.json lub programowo.

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

Jeśli ustawisz wartość AllowWebApiToBeAuthorizedByACLtruena , odpowiadasz za zapewnienie mechanizmu listy ACL.

Następne kroki

  • Dowiedz się więcej, tworząc aplikację internetową platformy ASP.NET Core, która loguje użytkowników w poniższej serii samouczków wieloczęściowych

  • Eksplorowanie przykładów internetowego interfejsu API Platforma tożsamości Microsoft