asp.net-mvc AllowAnonymous 不使用自定义 AuthorizationAttribute

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13595723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 02:26:13  来源:igfitidea点击:

AllowAnonymous not working with Custom AuthorizationAttribute

asp.net-mvcauthenticationattributesasp.net-web-api

提问by Jammer

This has had me stumped for a while. None of the commonly encountered similar situations seem to apply here apparently. I've probably missed something obvious but I can't see it.

这让我难住了一段时间。常见的类似情况似乎都不适用于这里。我可能错过了一些明显的东西,但我看不到它。

In my Mvc Web Application I use the Authorize and AllowAnonymous attributes in such a way that you have to explicitly open up an action as publicly available rather than lock down the secure areas of the site. I much prefer that approach. I cannot get the same behaviour in my WebAPI however.

在我的 Mvc Web 应用程序中,我以这样一种方式使用 Authorize 和 AllowAnonymous 属性,您必须明确地打开一个公开可用的操作,而不是锁定站点的安全区域。我更喜欢这种方法。但是,我无法在我的 WebAPI 中获得相同的行为。

I have written a custom Authorization Attribute that inherits from System.Web.Http.AuthorizeAttribute with the following:

我编写了一个从 System.Web.Http.AuthorizeAttribute 继承的自定义授权属性,如下所示:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class MyAuthorizationAttribute : System.Web.Http.AuthorizeAttribute

I have this registered as a filter:

我已将此注册为过滤器:

    public static void RegisterHttpFilters(HttpFilterCollection filters)
    {
        filters.Add(new MyAuthorizationAttribute());
    }

This all works as expected, actions are no longer available without credentials. The problem is that now the following method will not allow the AllowAnonymous attribute to do it's thing:

这一切都按预期工作,如果没有凭据,操作将不再可用。问题是现在下面的方法不允许 AllowAnonymous 属性来做它的事情:

[System.Web.Http.AllowAnonymous]
public class HomeController : ApiController
{
    [GET("/"), System.Web.Http.HttpGet]
    public Link[] Index()
    {
        return new Link[] 
        { 
            new SelfLink(Request.RequestUri.AbsoluteUri, "api-root"),
            new Link(LinkRelConstants.AuthorizationEndpoint, "OAuth/Authorize/", "authenticate"),
            new Link(LinkRelConstants.AuthorizationTokenEndpoint , "OAuth/Tokens/", "auth-token-endpoint")
        };
    }
}

The most common scenario seems to be getting the two Authorize / AllowAnonymous attributes mixed up. System.Web.Mvc is for web apps and System.Web.Http is for WebAPI (as I understand it anyway).

最常见的情况似乎是混淆了两个 Authorize / AllowAnonymous 属性。System.Web.Mvc 用于 Web 应用程序,而 System.Web.Http 用于 WebAPI(据我所知)。

Both of the Attributes I'm using are from the same namespace - System.Web.Http. I assumed that this would just inherit the base functionality and allow me to inject the code I need in the OnAuthotize method.

我使用的两个属性都来自同一个命名空间 - System.Web.Http。我认为这只会继承基本功能,并允许我在 OnAuthotize 方法中注入我需要的代码。

According to the documentation the AllowAnonymous attribute works inside the OnAuthorize method which I call immediately:

根据文档, AllowAnonymous 属性在我立即调用的 OnAuthorize 方法中起作用:

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

Any thought's would be really appreciated.

任何想法将不胜感激。

Has anyone encountered this problem before and found the root cause?

有没有人以前遇到过这个问题并找到了根本原因?

回答by Jammer

In the AuthorizeAttribute there is the following code:

在 AuthorizeAttribute 中有以下代码:

private static bool SkipAuthorization(HttpActionContext actionContext)
{
    Contract.Assert(actionContext != null);

    return actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()
               || actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
}

Include this method in your AuthorizeAttribute class then add the following to the top of your OnAuthorization method to skip authorization if any AllowAnonymous attributes are found:

将此方法包含在您的 AuthorizeAttribute 类中,然后将以下内容添加到 OnAuthorization 方法的顶部以在找到任何 AllowAnonymous 属性时跳过授权:

if (SkipAuthorization(actionContext)) return;

回答by g.breeze

ASP.NET MVC 4:

ASP.NET MVC 4:

bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
                         || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);

or

或者

 private static bool SkipAuthorization(AuthorizationContext filterContext)
    {
        Contract.Assert(filterContext != null);

        return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()
               || filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
    }

Soruce: http://weblogs.asp.net/jongalloway/asp-net-mvc-authentication-global-authentication-and-allow-anonymous

来源:http://weblogs.asp.net/jongalloway/asp-net-mvc-authentication-global-authentication-and-allow-anonymous

回答by Mike

Using C#6.0 Create a static class that extends the ActionExecutingContext.

使用 C#6.0 创建一个扩展 ActionExecutingContext 的静态类。

public static class AuthorizationContextExtensions {
    public static bool SkipAuthorization(this ActionExecutingContext filterContext) {    
         Contract.Assert(filterContext != null);
         return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()|| filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
    }
}

Now your override filterContext will be able to call the extension method, just make sure they are in the same namespace, or include the proper using statement.

现在您的覆盖 filterContext 将能够调用扩展方法,只需确保它们在相同的命名空间中,或者包含正确的 using 语句。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeCustomAttribute : ActionFilterAttribute {
    public override void OnActionExecuting(ActionExecutingContext filterContext) {
        if (filterContext.SkipAuthorization()) return;// CALL EXTENSION METHOD
         /*NOW DO YOUR LOGIC FOR NON ANON ACCESS*/
    }
}

回答by Action Dan

I must be using a different version of the .net framework or web api but hopefully this helps someone:

我必须使用不同版本的 .net 框架或 web api,但希望这对某人有所帮助:

        bool skipAuthorization = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
        if (skipAuthorization)
        {
            return;
        }

回答by Suvenjeet

public class MyAuthorizationAuthorize : AuthorizeAttribute, IAuthorizationFilter
{
public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAuthenticated)
            {
                bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
                    filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);

                if (skipAuthorization) return;

            }
            else filterContext.Result = new HttpUnauthorizedResult();
        }
}

回答by krishna rajan

Using MVC 5
Steps to overcome this issue:-
1. Update your Anonymous attribute of WebAPI project and make it like

使用 MVC 5
步骤来克服这个问题:-
1. 更新您的 WebAPI 项目的匿名属性并使其像

[System.Web.Mvc.AllowAnonymous]
  1. Now go to your custom attribute class and write the code

     public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext filterContext)
    {
        if (filterContext == null)
        {
            throw new UnauthorizedAccessException("Access Token Required");
        }
        base.OnAuthorization(filterContext);
        if (filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
        {
            return;
        }
        if (filterContext.Request.Headers.Authorization != null)
        {
            var response = 
     PTPRestClient.GetRequest(filterContext.Request.Headers.Authorization.ToString(), 
     "api/validate/validate-request");
            if (!response.IsSuccessStatusCode)
            {
                throw new UnauthorizedAccessException();
            }
    
    
        }
        else
        {
            throw new UnauthorizedAccessException("Access Token Required");
        }
    }
    
  1. 现在转到您的自定义属性类并编写代码

     public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext filterContext)
    {
        if (filterContext == null)
        {
            throw new UnauthorizedAccessException("Access Token Required");
        }
        base.OnAuthorization(filterContext);
        if (filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
        {
            return;
        }
        if (filterContext.Request.Headers.Authorization != null)
        {
            var response = 
     PTPRestClient.GetRequest(filterContext.Request.Headers.Authorization.ToString(), 
     "api/validate/validate-request");
            if (!response.IsSuccessStatusCode)
            {
                throw new UnauthorizedAccessException();
            }
    
    
        }
        else
        {
            throw new UnauthorizedAccessException("Access Token Required");
        }
    }