我创建了一个自定义授权属性,但我需要一些操作来允许匿名访问。我尝试了三种不同的方法但未成功:使用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
}
}
作为最后的手段,我可以将登录操作移动到他们自己的控制器上,但在我这样做之前,我是否遗漏了一些东西以使其中一种方法起作用?我有点惊讶于动作级属性不会覆盖控制器级属性。
答案 0 :(得分:2)
OnAuthorization
method of AuthorizeAttribute
的实施扫描AllowAnonymousAttribute
。因此,您必须不覆盖此方法,或者如果您希望该部分工作,请重新执行此检查。由于您只提供了AuthorizeAttribute
的简化实现,因此不能假设您没有覆盖此方法(从而覆盖了进行检查的逻辑)。
此外,您的示例控制器实际上并未显示AllowAnonymousAttribute
的使用情况。相反,它设置名为AllowAnonymous
的属性。如果您希望匿名用户访问该操作方法,则应使用MVC实际扫描的属性对其进行修饰。
[AuthorizePublic(Sites = AuthSites.Corporate)]
public class CorporateController : SecuredController
{
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
}
或者,如果您需要以某种方式自定义AllowAnonymous
行为,您可以继续使用您拥有的属性,但您必须自己实施Reflection代码以扫描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
同时实现Attribute
和IAuthorizationFilter
。考虑到这一点,IAuthorizationFilter
的{{1}}部分是与<{1}}部分不同的类运行时实例。因此前者必须使用Reflection来读取后者的属性才能使其工作。您不能只从当前实例中读取AuthorizeAttribute
属性并期望它可以工作,因为您正在设置属性中的值,并且代码正在过滤器中执行。
MVC和Web API是完全独立的框架,具有各自独立的配置,即使它们可以在同一个项目中共存。 MVC将完全忽略Web API中定义的任何控制器或属性,反之亦然。