59

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

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

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

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

我已将此注册为过滤器:

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

这一切都按预期工作,没有凭据将不再可用。问题是现在以下方法将不允许 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")
        };
    }
}

最常见的情况似乎是混淆了两个 Authorize / AllowAnonymous 属性。System.Web.Mvc 用于 Web 应用程序,而 System.Web.Http 用于 WebAPI(无论如何我都理解)。

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

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

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

任何想法将不胜感激。

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

4

8 回答 8

98

在 AuthorizeAttribute 中有以下代码:

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

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

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

if (SkipAuthorization(actionContext)) return;
于 2012-11-28T00:42:55.183 回答
36

ASP.NET MVC 4:

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

或者

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

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

于 2014-12-01T10:52:20.100 回答
13

就我而言,上述解决方案均无效。我正在使用带有自定义功能的 .Net Core 3.1,IAuthorizationFilter我必须执行以下操作:

public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any()) return;
于 2020-09-17T14:24:33.933 回答
3

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

[System.Web.Mvc.AllowAnonymous]
  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");
        }
    }
    
于 2018-10-30T05:46:55.897 回答
2

这是 ASP.NET Core 2+ 和 ASP.NET Core 3+ 的解决方案。将其添加到 IAsyncAuthorizationFilter 实现中:

private static bool HasAllowAnonymous(AuthorizationFilterContext context)
{
    var filters = context.Filters;
    return filters.OfType<IAllowAnonymousFilter>().Any();
}

并像这样检查:

public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
    if(HasAllowAnonymous(context))
        return;
}
于 2020-06-03T11:28:36.947 回答
1

使用 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();
    }
}

现在您的覆盖 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*/
    }
}
于 2017-04-28T16:49:53.943 回答
0

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

        bool skipAuthorization = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
        if (skipAuthorization)
        {
            return;
        }
于 2017-08-28T09:36:00.910 回答
0
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();
        }
}
于 2018-08-16T11:02:11.877 回答