Autorização personalizada em Asp.net WebApi - que bagunça?

113

Estou lendo vários recursos (livros e respostas do SO) sobre autorização no WebApi.

Suponha que eu queira adicionar um atributo personalizado que permite o acesso apenas para determinados usuários:

Caso 1

Já vi essa abordagem de substituição OnAuthorization , que define a resposta se algo estiver errado

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

Caso # 2

Mas eu também vi este exemplo semelhante que também substitui, OnAuthorizationmas chama para base:

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

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

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

Em seguida, você verifica se o HttpActionContext.Responseestá configurado ou não. Se não estiver definido, significa que a solicitação está autorizada e o usuário está ok

Caso # 3

Mas também vi essa abordagem de substituição IsAuthorized :

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

Caso # 4

E então eu vi um exemplo semelhante, mas com base de chamada.IsAuthorized (contexto):

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

Mais uma coisa

E finalmente Dominick disse aqui :

Você não deve substituir OnAuthorization - porque você estaria perdendo o tratamento de [AllowAnonymous].

Questões

  • 1) Quais métodos devo usar: IsAuthorizedou OnAuthorization? (ou quando usar qual)

  • 2) quando devo chamar base.IsAuthorized orbase.OnAuthorization`?

  • 3) É assim que eles o construíram? que se a resposta for nula está tudo bem? (caso 2)

NB

Observe, estou usando (e quero usar) apenas o AuthorizeAttributeque já herda de AuthorizationFilterAttribute

Por quê ?

Porque estou no primeiro estágio em: http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

insira a descrição da imagem aqui

De qualquer forma, estou perguntando através da extensão do atributo Autorizar.

Royi Namir
fonte
O que você precisa para substituir o atributo Authorize? Qual é o caso de uso que você deseja alcançar? Se você precisa permitir o acesso para certos usuários, por que não usar o atributo [Authorize (Users = "Admin")] assim?
Taiseer Joudeh
1
@TaiseerJoudeh Por exemplo, tente autorizar usuários entre 10:00 e 12:00 (configurável). você não pode fazer isso com funções simples e atributos autorizados. você tem que fazer sua própria lógica
Royi Namir

Respostas:

93

Quais métodos devo usar: IsAuthorized ou OnAuthorization? (ou quando usar qual)

Você estenderá AuthorizationFilterAttributese sua lógica de autorização não depender da identidade estabelecida e das funções. Para autorização relacionada ao usuário, você irá estender e usar AuthorizeAttribute. Para o primeiro caso, você substituirá OnAuthorization. Para o último caso, você substituirá IsAuthorized. Como você pode ver no código-fonte desses atributos, OnAuthorizationestá marcado como virtual para você substituir se derivar AuthorizationFilterAttribute. Por outro lado, o IsAuthorizedmétodo é marcado como virtual em AuthorizeAttribute. Acredito que este seja um bom indicador do uso pretendido.

quando devo chamar base.IsAuthorized ou base.OnAuthorization?

A resposta a essa pergunta está em como OO geralmente funciona. Se você substituir um método, poderá fornecer completamente uma nova implementação ou pegar carona na implementação fornecida pelo pai e aprimorar o comportamento. Por exemplo, considere o caso de IsAuthorized(HttpActionContext). O comportamento da classe base é verificar o usuário / função em relação ao que está especificado no filtro e a identidade estabelecida. Digamos que você queira fazer tudo isso, mas, além disso, deseja verificar outra coisa, pode ser baseado em um cabeçalho de solicitação ou algo assim. Nesse caso, você pode fornecer uma substituição como esta.

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;
}

Sinto muito, mas não entendi seu Q3. BTW, o filtro de autorização existe há muito tempo e as pessoas o usam para todos os tipos de coisas e às vezes incorretamente também.

Mais uma coisa. E, finalmente, havia um cara aqui que disse: Você não deve substituir OnAuthorization - porque você perderia o manuseio de [AllowAnonymous].

O cara que disse isso é o Deus do controle de acesso - Dominick. Obviamente, estará correto. Se você olhar para a implementação de OnAuthorization(copiado abaixo),

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

    if (SkipAuthorization(actionContext))
    {
        return;
    }

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

a chamada para SkipAuthorizationé a parte que garante a aplicação dos AllowAnonymousfiltros, ou seja, a autorização é ignorada. Se você substituir esse método, perderá esse comportamento. Na verdade, se você decidir basear sua autorização em usuários / funções, nesse ponto você terá decidido derivar AuthorizeAttribute. Nesse ponto, a única opção correta deixada para você será substituirIsAuthorized e não a já substituída OnAuthorization, embora seja tecnicamente possível fazer qualquer um.

PS. Na API Web ASP.NET, há outro filtro chamado filtro de autenticação. A ideia é que você use isso para autenticação e filtro de autorização para autorização, como o nome indica. No entanto, existem muitos exemplos em que esse limite é distorcido. Muitos exemplos de filtros de autenticação farão algum tipo de autenticação. De qualquer forma, se você tiver tempo e quiser entender um pouco mais, dê uma olhada neste artigo do MSDN . Disclaimer: Foi escrito por mim.

Badri
fonte
Obrigado novamente, mas se eu ler nas entrelinhas, IsAuthenticated é chamado por OnAuthirization, então por que não substituir OnAuthorization e chamar base.OnAuthorization e depois verificar a resposta?
Royi Namir
Você com certeza pode, se é isso que você deseja.
Badri de
Na minha terceira pergunta, eu quis dizer: depois de executar a função base - base.OnAuthorization por exemplo, a única maneira de verificar se foi bem-sucedido - é inspecionar a propriedade Response ?, ps os exemplos são do seu livro :-)
Royi Namir
Sim, normalmente você procura o código de status 401, mas não nulo, pelo que eu sei. BTW, não me lembro de ter escrito sobre substituir OnAuthorizationno meu livro. Tenho certeza de que não teria escrito sobre a verificação de resposta para nulo, porque esta é a primeira vez que ouço sobre isso :)
Badri
Sim, me confundi com o outro livro. Estou lendo 3 livros simultaneamente: securty (seu), prático (seu) e webapi pro (Tugberk's, Zeitler, Ali). COMO você pode ver - eles fizeram isso lá: i.stack.imgur.com/LNGi4.jpg - eles apenas verificaram se nulo, então devo verificar códigos nulos ou de erro?
Royi Namir de
18

Ok, minha sugestão é fazer o seguinte presumindo que você está usando tokens de portador OAuth para proteger sua API da Web e está configurando o allowedTime como uma declaração para o usuário quando você emitiu o token. Você pode ler mais sobre autenticação baseada em tokens aqui

  1. Crie CustomAuthorizeAttribute que deriva de AuthorizationFilterAttribute
  2. método de substituição OnAuthorizationAsynce use o código de amostra abaixo:

     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. Agora em seus controladores você usa o atributo CustomAuthorize para proteger seus controladores usando essa lógica de autorização.
Taiseer Joudeh
fonte
1
Obrigado. Mas atualmente estou usando o AuthorizeAttributeque herda AuthorizationFilterAttributee -também para aprender, perguntei especificamente sobre qual método devo usar e sobre a Resposta ter conteúdo ou não ...
Royi Namir
3

ASP.NET v5 introduziu um sistema de autorização completamente novo. Para aqueles que vão usar o .NET 5, eu sugiro mudar para Microsoft.AspNet.Authorization.

Muito bonito isso envolve a bagunça causada por manter ambos System.Web.Http.AuthorizeeSystem.Web.Mvc.Authorize e outras implementações de autenticação mais velhos.

Ele fornece uma abstração muito boa de Tipos de Ação (Criar, Ler, Atualizar, Excluir), Recursos, Funções, Reivindicações, Visualizações, Requisitos Customizados e permite construir Manipuladores customizados, combinando qualquer um dos anteriores. Além disso, esses manipuladores também podem ser usados ​​em combinação.

No ASP.NET v5, a autorização agora fornece uma função declarativa simples e um modelo baseado em política mais rico, em que a autorização é expressa em requisitos e os manipuladores avaliam as reivindicações dos usuários em relação aos requisitos. As verificações imperativas podem ser baseadas em políticas simples ou políticas que avaliam a identidade do usuário e as propriedades do recurso que o usuário está tentando acessar.

Anestis Kivranoglou
fonte
14
É bom saber, mas não responde à pergunta.
Zero3 de