这让我难以忍受了一段时间。通常遇到的类似情况似乎都不适用于此。我可能错过了一些明显但我看不到的东西。
在我的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);
任何想法都会非常感激。
之前是否有人遇到此问题并找到根本原因?
答案 0 :(得分:79)
在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;
答案 1 :(得分:24)
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();
}
答案 2 :(得分:3)
就我而言,以上解决方案均无效。
我正在使用带有自定义IAuthorizationFilter
的.Net Core 3.1,并且必须执行以下操作:
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any()) return;
答案 3 :(得分: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*/
}
}
答案 4 :(得分:1)
这是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;
}
答案 5 :(得分:0)
我必须使用不同版本的.net框架或web api,但希望这有助于某人:
SELECT *
FROM english
WHERE
words REGEXP '^.*[aeiou]{2}.*$' AND
words NOT REGEXP '^.*[aeiou]{3}.*$'
答案 6 :(得分: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();
}
}
答案 7 :(得分:0)
使用MVC 5
解决此问题的步骤:-
1.更新您的WebAPI项目的Anonymous属性并将其设置为
[System.Web.Mvc.AllowAnonymous]
现在转到您的自定义属性类并编写代码
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");
}
}