Pergunta

já revi meu código um milhão de vezes e não consigo encontrar nenhum problema com minha implementação.

no AuthorizeAttribute personalizado eu substituí 2 métodos

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (!httpContext.Request.IsAuthenticated)
            return false;
        var routeData = httpContext.Request.RequestContext.RouteData;
        var ctrl = routeData.Values["controller"].ToString();
        var action = routeData.Values["action"].ToString();
        var user = httpContext.User.Identity.Name;
        _logger.Info("[logging all the details]");
        return ctrl == "SomeController";
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext ctx)
    {
        ctx.Result = new ViewResult  { ViewName = "Unauthorized" };
        // base.HandleUnauthorizedRequest(ctx);
     }

a lógica de autorização é simulada para retornar falso apenas em um controlador específico, e passei por isso para verificar se está funcionando corretamente.

o código acima causará um loop infinito.no meu log posso ver aquela linha atingida 666 vezes (coincidência?) ..

se eu ligar para base.HandleUnauthorizedRequest (ctx), tudo que recebo é uma página em branco.então eu refleti sobre o que a base faz, e é isso

filterContext.Result = new HttpUnauthorizedResult();

então isso explica por que ele renderiza uma página em branco em vez de redirecionar para Unauthorized.cshtml.o que não tenho certeza é por que ele entra em um loop infinito se eu não chamo a base.

p.s.

verifiquei que se eu colocar a visualização não autorizada errada, ocorrerá um erro (mas ainda travará indefinidamente)

 System.InvalidOperationException: The view 'Unauthorized11' or its master was not found or no view engine supports the searched locations
Foi útil?

Solução

Aqui está a implementação que acabei adotando e está funcionando muito bem.

    public override void OnAuthorization(AuthorizationContext filterContext)
    {

        base.OnAuthorization(filterContext);

        // this is overriden for kendo menus to hide 
        var ctrl = filterContext.RequestContext.RouteData.GetRequiredString("controller");
        var action = filterContext.ActionDescriptor.ActionName;

        [custom authorization logic on action/ctrl]

        // useful to determine if it's authorizing current controller path or menu links
        var path = filterContext.HttpContext.Request.PhysicalPath;
        _authorizingCurrentPath = path.Contains(ctrl) || path.EndsWith("WebUI") ;


        if (userAuth < requiredAuth)
            HandleUnauthorizedRequest(filterContext);
    }


    protected override void HandleUnauthorizedRequest(AuthorizationContext ctx)
    {
        if (!ctx.HttpContext.User.Identity.IsAuthenticated)
            base.HandleUnauthorizedRequest(ctx);
        else {
            if (_authorizingCurrentPath) {
                // handle controller access
                ctx.Result = new ViewResult { ViewName = "Unauthorized" };
                ctx.HttpContext.Response.StatusCode = 403;
            }
            else {
                // handle menu links
                ctx.Result = new HttpUnauthorizedResult();
                ctx.HttpContext.Response.StatusCode = 403;
            }
        }
    }

Outras dicas

A implementação padrão de AutorizarAtributo define a resposta no contexto da ação, ao não chamar a base a resposta nunca é definida, o que faz com que o filtro repita o processo de autorização até que uma resposta seja definida (daí o loop infinito).

Você pode ver essa lógica no AuthorizationFilterAttribute classe da qual AuthorizeAttribute deriva.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top