【问题标题】:Get MVC AllowAnonymous to override custom authorize attribute获取 MVC AllowAnonymous 以覆盖自定义授权属性
【发布时间】:2018-01-22 12:46:47
【问题描述】:

我创建了一个自定义授权属性,但我需要一些操作来允许匿名访问。我尝试了三种不同的方法,但均未成功:使用AllowAnonymous,使用附加参数更新现有属性,并创建一个新的覆盖属性。基本上,控制器级属性似乎总是​​在动作级属性之前被调用。

这是控制器:

[AuthorizePublic(Sites = AuthSites.Corporate)]
public class CorporateController : SecuredController
{
    [AuthorizePublic(Sites = AuthSites.Corporate, AllowAnonymous = true)]
    public ActionResult Login(string returnUrl)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }
}

以及属性:

public class AuthorizePublic : AuthorizeAttribute
{
    public AuthSites Sites { get; set; }
    public bool AllowAnonymous { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        // Logic
    }        
}

作为最后的手段,我可​​以将登录操作移动到他们自己的控制器上,但在我这样做之前,我是否遗漏了一些东西来让这些方法中的一种工作?动作级别的属性没有覆盖控制器级别的属性,这让我有点惊讶。

【问题讨论】:

  • 只是为了确认一下,Action 方法上的简单[AllowAnonymous] 在您的情况下不会覆盖 Authorization 属性?
  • 已确认。如果我调试,我可以看到它正在访问控制器属性并陷入重定向循环。
  • 所以问题似乎不是授权,而是重定向循环 - 这不应该发生。愿意在您的问题中填写一些详细信息吗?也许向我们购买您的 AuthorizeCore 方法的代码,或者导致重定向的任何原因
  • 我听到了你的理论,但我只是删除了控制器上的属性,并且操作上的自定义属性被完全忽略了。也许我需要更新我的属性实现以表明它也可以用于操作?
  • 你也可以试试this回答。可能会有所帮助。

标签: asp.net-mvc


【解决方案1】:

扫描AllowAnonymousAttribute的是OnAuthorization method of AuthorizeAttribute的实现。因此,如果您希望该部分正常工作,您必须不覆盖此方法或重新实现此检查。由于您只提供了AuthorizeAttribute 的精简实现,因此不能假设您没有覆盖此方法(从而覆盖进行检查的逻辑)。

此外,您的示例控制器实际上并未显示AllowAnonymousAttribute 的用法。相反,它设置了一个名为AllowAnonymous 的属性。如果您希望匿名用户访问该操作方法,您应该使用 MVC 实际扫描的属性来装饰它。

[AuthorizePublic(Sites = AuthSites.Corporate)]
public class CorporateController : SecuredController
{
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }
}

或者,如果您需要以某种方式自定义AllowAnonymous 行为,您可以继续使用您拥有的属性,但您必须自己实现反射代码以扫描AuthorizePublic 并检查AllowAnonymous 属性.

public class AuthorizePublic : AuthorizeAttribute
{
    public AuthSites Sites { get; set; }
    public bool AllowAnonymous { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var actionDescriptor = httpContext.Items["ActionDescriptor"] as ActionDescriptor;
        if (actionDescriptor != null)
        {
            AuthorizePublic attribute = GetAuthorizePublicAttribute(actionDescriptor);
            if (attribute.AllowAnonymous)
                return true;

            var sites = attribute.Sites;

            // Logic
        }
        return true;
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        // Pass the current action descriptor to the AuthorizeCore
        // method on the same thread by using HttpContext.Items
        filterContext.HttpContext.Items["ActionDescriptor"] = filterContext.ActionDescriptor;
        base.OnAuthorization(filterContext);
    }

    // Gets the Attribute instance of this class from an action method or contoroller.
    // An action method will override a controller.
    private AuthorizePublic GetAuthorizePublicAttribute(ActionDescriptor actionDescriptor)
    {
        AuthorizePublic result = null;

        // Check if the attribute exists on the action method
        result = (AuthorizePublic)actionDescriptor
            .GetCustomAttributes(attributeType: typeof(AuthorizePublic), inherit: true)
            .SingleOrDefault();

        if (result != null)
        {
            return result;
        }

        // Check if the attribute exists on the controller
        result = (AuthorizePublic)actionDescriptor
            .ControllerDescriptor
            .GetCustomAttributes(attributeType: typeof(AuthorizePublic), inherit: true)
            .SingleOrDefault();

        return result;
    }
}

AuthorizeAttribute 实现了AttributeIAuthorizationFilter。考虑到这一点,AuthorizeAttributeIAuthorizationFilter 部分与Attribute 部分相比是类的不同运行时实例。所以前者必须使用反射来读取后者的属性才能使其工作。您不能只从当前实例中读取 AllowAnonymous 属性并期望它工作,因为您在属性中设置值并且代码正在过滤器中执行。

MVC 和 Web API 是完全独立的框架,具有各自独立的配置,即使它们可以共存于同一个项目中。 MVC 将完全忽略 Web API 中定义的任何控制器或属性,反之亦然。

【讨论】:

  • 详细的解释,谢谢 - 覆盖属性的读取对我有用
猜你喜欢
  • 2015-11-04
  • 1970-01-01
  • 1970-01-01
  • 2015-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-16
  • 2013-11-09
相关资源
最近更新 更多