我已经创建了一个自定义授权属性,但我需要一些操作来允许匿名访问。我尝试了三种不同的方法,但没有成功:使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
以及属性:
public class AuthorizePublic : AuthorizeAttribute
{
public AuthSites Sites { get; set; }
public bool AllowAnonymous { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// Logic
}
}
Run Code Online (Sandbox Code Playgroud)
作为最后的手段,我可以将登录操作移动到它们自己的控制器上,但在这样做之前,我是否缺少一些东西来使这些方法之一发挥作用?我有点惊讶的是操作级属性并没有覆盖控制器级属性。
它是扫描OnAuthorization的方法 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();
}
}
Run Code Online (Sandbox Code Playgroud)
或者,如果您需要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;
}
}
Run Code Online (Sandbox Code Playgroud)
AuthorizeAttribute实现Attribute和IAuthorizationFilter。考虑到这一点,IAuthorizationFilter的部分AuthorizeAttribute是类的与Attribute部分不同的运行时实例。所以前者必须使用反射来读取后者的属性才能工作。您不能只AllowAnonymous从当前实例中读取属性并期望它起作用,因为您正在属性中设置值并且代码正在过滤器中执行。
MVC 和 Web API 是完全独立的框架,具有各自独立的配置,尽管它们可以共存于同一项目中。MVC 将完全忽略 Web API 中定义的任何控制器或属性,反之亦然。
| 归档时间: |
|
| 查看次数: |
3215 次 |
| 最近记录: |