Autoryzacja niestandardowa w Asp.net WebApi - co za bałagan?

113

Czytam z kilku źródeł (książek i odpowiedzi SO) na temat autoryzacji w WebApi.

Załóżmy, że chcę dodać atrybut niestandardowy, który umożliwia dostęp tylko dla niektórych użytkowników:

Przypadek 1

Widziałem takie podejście do nadpisywania OnAuthorization , które ustawia odpowiedź, jeśli coś jest nie tak

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 public override void OnAuthorization(HttpActionContext actionContext)
  {
   if ( /*check if user OK or not*/)
   {
     actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
   }
  }
}

Przypadek 2

Ale widziałem też ten podobny przykład, który również jest nadrzędny, OnAuthorizationale z wzywaniem do base:

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
  base.OnAuthorization(actionContext);

    // If not authorized at all, don't bother

    if (actionContext.Response == null)  
     {
      //...
     }
}

Następnie sprawdzasz, czy HttpActionContext.Responsejest ustawiony, czy nie. Jeśli nie jest ustawiona, oznacza to, że żądanie jest autoryzowane, a użytkownik jest w porządku

Przypadek 3

Ale widziałem też takie podejście do zastępowania IsAuthorized :

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 protected override bool IsAuthorized(HttpActionContext context)
  {
   if ( /*check if user OK or not*/)
   {
    return true;// or false
   }
  }
}

Przypadek 4

I wtedy zobaczyłem podobny przykład, ale z wywoływaniem bazy.IsAuthorized (context):

protected override bool IsAuthorized(HttpActionContext context)
{
 if (something1 && something2 && base.IsAuthorized(context)) //??
 return true;
 return false;
}

Jeszcze jedna rzecz

I wreszcie Dominick powiedział tutaj :

Nie należy nadpisywać OnAuthorization - ponieważ brakowałoby obsługi [AllowAnonymous].

pytania

  • 1) Jakich metod powinienem użyć: IsAuthorizedlub OnAuthorization? (lub kiedy użyć którego)

  • 2) kiedy powinienem zadzwonić do base.IsAuthorized orbazy OnAuthorization?

  • 3) Czy tak to zbudowali? że jeśli odpowiedź jest zerowa, to wszystko jest w porządku? (sprawa nr 2)

NB

Proszę zauważyć, że używam (i chcę używać) tylko tego, AuthorizeAttributeco już dziedziczy z AuthorizationFilterAttribute

Czemu ?

Ponieważ jestem na pierwszym etapie w: http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

wprowadź opis obrazu tutaj

W każdym razie pytam przez rozszerzenie atrybutu Authorize.

Royi Namir
źródło
Czego potrzebujesz, aby zastąpić atrybut Autoryzuj? Jaki jest przypadek, który chcesz osiągnąć? Jeśli chcesz zezwolić na dostęp określonym użytkownikom, dlaczego nie użyć atrybutu [Autoryzuj (Użytkownicy = "Administrator")] w ten sposób?
Taiseer Joudeh
1
@TaiseerJoudeh Na przykład Spróbuj autoryzować użytkowników między 10:00 a 12:00 (konfigurowalne). nie możesz tego zrobić ze zwykłymi rolami i autoryzowanym atrybutem. musisz stworzyć własną logikę
Royi Namir

Odpowiedzi:

93

Których metod powinienem użyć: IsAuthorized czy OnAuthorization? (lub kiedy użyć którego)

Rozszerzysz zakres, AuthorizationFilterAttributejeśli logika autoryzacji nie jest zależna od ustalonej tożsamości i ról. Aby uzyskać autoryzację związaną z użytkownikiem, możesz rozszerzyć i używać AuthorizeAttribute. W pierwszym przypadku zastąpisz OnAuthorization. W tym drugim przypadku zastąpisz IsAuthorized. Jak widać z kodu źródłowego tych atrybutów, OnAuthorizationjest oznaczony jako wirtualny, abyś mógł go zastąpić, jeśli pochodzi z AuthorizationFilterAttribute. Z drugiej strony IsAuthorizedmetoda jest oznaczona jako wirtualna w AuthorizeAttribute. Uważam, że jest to dobra wskazówka do zamierzonego użycia.

kiedy mam zadzwonić do base.IsAuthorized lub base.OnAuthorization?

Odpowiedź na to pytanie leży w tym, jak ogólnie działa OO. Jeśli nadpisujesz metodę, możesz albo całkowicie zapewnić nową implementację, albo skorzystać z implementacji dostarczonej przez rodzica i poprawić zachowanie. Na przykład weźmy przypadek IsAuthorized(HttpActionContext). Zachowanie klasy bazowej polega na sprawdzeniu użytkownika / roli pod kątem tego, co określono w filtrze, w porównaniu z ustaloną tożsamością. Powiedzmy, że chcesz to wszystko zrobić, ale dodatkowo chcesz sprawdzić coś innego, może to być oparte na nagłówku żądania lub czymś podobnym. W takim przypadku możesz wprowadzić takie zastąpienie.

protected override bool IsAuthorized(HttpActionContext actionContext)
{
    bool isAuthroized = base.IsAuthorized(actionContext);
    // Here you look at the header and do your additional stuff based on actionContext
    // and store the result in isRequestHeaderOk
    // Then, you can combine the results
    // return isAuthorized && isRequestHeaderOk;
}

Przepraszam, ale nie rozumiem twojego Q3. Przy okazji, filtr autoryzacji istnieje od dawna i ludzie używają go do różnych rzeczy, a czasem także niepoprawnie.

Jeszcze jedna rzecz. I w końcu był tutaj ten facet, który powiedział: Nie powinieneś zastępować OnAuthorization - ponieważ straciłbyś obsługę [AllowAnonymous].

Facet, który to powiedział, to Bóg kontroli dostępu - Dominick. Oczywiście będzie to poprawne. Jeśli spojrzysz na implementację OnAuthorization(skopiowane poniżej),

public override void OnAuthorization(HttpActionContext actionContext)
{
    if (actionContext == null)
    {
        throw Error.ArgumentNull("actionContext");
    }

    if (SkipAuthorization(actionContext))
    {
        return;
    }

    if (!IsAuthorized(actionContext))
    {
        HandleUnauthorizedRequest(actionContext);
    }
}

wywołanie SkipAuthorizationjest częścią zapewniającą AllowAnonymousstosowanie filtrów, to znaczy, że autoryzacja jest pomijana. Jeśli zmienisz tę metodę, utracisz to zachowanie. Właściwie, jeśli zdecydujesz się oprzeć swoją autoryzację na użytkownikach / rolach, w tym momencie zdecydowałbyś się wyprowadzić AuthorizeAttribute. W tym momencie jedyną właściwą opcją będzie zastąpienie, IsAuthorizeda nie już zastąpiona OnAuthorization, chociaż jest to technicznie możliwe.

PS. W interfejsie API sieci Web ASP.NET istnieje inny filtr o nazwie filtr uwierzytelniania. Chodzi o to, że używasz tego do uwierzytelniania i filtru autoryzacji do autoryzacji, jak wskazuje nazwa. Istnieje jednak wiele przykładów, w których ta granica jest sfałszowana. Wiele przykładów filtrów autoryzacji wykonuje pewnego rodzaju uwierzytelnianie. Tak czy inaczej, jeśli masz czas i chcesz dowiedzieć się czegoś więcej, zapoznaj się z tym artykułem MSDN . Zastrzeżenie: zostało napisane przeze mnie.

Badri
źródło
Jeszcze raz dziękuję, ale jeśli czytam między wierszami, IsAuthenticated jest wywoływany przez OnAuthirization, więc dlaczego nie zastąpić OnAuthorization i call base.OnAuthorization, a następnie sprawdzić odpowiedź?
Royi Namir
Na pewno możesz, jeśli tego chcesz.
Badri
W trzecim pytaniu miałem na myśli: po uruchomieniu funkcji bazowej - np. Base.OnAuthorization czy jedynym sposobem sprawdzenia, czy się powiodło - jest sprawdzenie właściwości Response ?, ps przykłady pochodzą z twojej książki :-)
Royi Namir
Tak, zazwyczaj szukasz kodu statusu 401, ale nie null, o ile wiem. Przy okazji, nie pamiętam, żebym pisał o nadpisywaniu OnAuthorizationw mojej książce. Jestem pewien, że nie napisałbym o sprawdzaniu odpowiedzi na null, bo to pierwszy raz, kiedy o tym słyszę :)
Badri
Tak, pomyliłem się z drugą książką. Czytam jednocześnie 3 książki: securty (twoja), praktyczna (twoja) i webapi pro (Tugberk's, Zeitler, Ali). Jak widać - zrobili to tam: i.stack.imgur.com/LNGi4.jpg - właśnie sprawdzili, czy jest pusty, więc czy powinienem sprawdzić kody zerowe lub kody błędów?
Royi Namir
18

Ok, moja sugestia jest taka, aby wykonać następujące czynności, zakładając, że używasz tokenów okaziciela OAuth do ochrony swojego internetowego interfejsu API i ustawiasz allowedTime jako żądanie dla użytkownika podczas wystawiania tokenu. Możesz przeczytać więcej o uwierzytelnianiu za pomocą tokenów tutaj

  1. Utwórz CustomAuthorizeAttribute, który pochodzi z AuthorizationFilterAttribute
  2. override OnAuthorizationAsynci użyj przykładowego kodu poniżej:

     public class CustomAuthorizeAttribute : AuthorizationFilterAttribute
    {
    
        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
    
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (!principal.Identity.IsAuthenticated)
            {
                return Task.FromResult<object>(null);
            }
    
            var userName = principal.FindFirst(ClaimTypes.Name).Value;
            var userAllowedTime = principal.FindFirst("userAllowedTime").Value;
    
            if (currentTime != userAllowedTime)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Not allowed to access...bla bla");
                return Task.FromResult<object>(null);
            }
    
            //User is Authorized, complete execution
            return Task.FromResult<object>(null);
    
        }
    }
    
  3. Teraz w kontrolerach używasz atrybutu CustomAuthorize do ochrony kontrolerów za pomocą tej logiki autoryzacji.
Taiseer Joudeh
źródło
1
Dzięki. Ale obecnie używam tego, AuthorizeAttributeco dziedziczy AuthorizationFilterAttributei - również do nauki, zapytałem konkretnie, której metody powinienem użyć, a odpowiedź ma treść lub nie ma rzeczy ...
Royi Namir
3

ASP.NET v5 Wprowadził zupełnie nowy system autoryzacji. Dla tych, którzy zamierzają korzystać z .NET 5, sugerowałbym przejście na Microsoft.AspNet.Authorization.

Dość dużo owija bałaganu spowodowanego zarówno utrzymanie System.Web.Http.Authorizei System.Web.Mvc.Authorizei inne starsze implementacje uwierzytelniania.

Zapewnia bardzo dobrą abstrakcję typów akcji (tworzenie, odczytywanie, aktualizowanie, usuwanie), zasobów, ról, roszczeń, widoków, wymagań niestandardowych i pozwala budować niestandardowe programy obsługi, łącząc dowolne z powyższych. Ponadto te uchwyty mogą być również używane w połączeniu.

W ASP.NET v5 autoryzacja zapewnia teraz prostą rolę deklaratywną i bogatszy model oparty na zasadach, w którym autoryzacja jest wyrażona w wymaganiach, a programy obsługi oceniają oświadczenia użytkowników względem wymagań. Weryfikacje bezwzględne mogą opierać się na prostych zasadach lub zasadach, które oceniają zarówno tożsamość użytkownika, jak i właściwości zasobu, do którego użytkownik próbuje uzyskać dostęp.

Anestis Kivranoglou
źródło
14
Dobrze wiedzieć, ale w ogóle nie odpowiada na pytanie.
Zero3