在 OnAuthorization 之前执行的 ASP.NET MVC Global 或 BaseController ActionFilter
在我的应用程序(ASP.NET MVC 3)中,我有一个 BaseController 类,我的所有控制器都继承该类,并且在该 BaseController 中,我重写了 OnActionExecuting 方法来检查以确保填充 Session 变量,因为我需要在所有其他操作方法中访问该变量在应用程序中。我还定义了一个扩展 AuthorizeAttributeClass 的自定义 Authorize 属性。在该属性中,我重写 OnAuthorization 以检查我在 BaseController OnActionExecuting 方法中加载的同一会话变量,以查看是否应允许用户继续。
BaseController
public class BaseController : Controller
{
private ISessionUserService sessionUserService;
public BaseController(ISessionUserService sessionUserService)
{
this.sessionUserService = sessionUserService;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (User != null && User.Identity.IsAuthenticated && this.sessionUserService.Current == null)
{
this.sessionUserService.Start(accountID, User.Identity.Name);
// If we weren't successful in reloading the SessionUser
// variable, redirect the user to the Sign In view
if (this.sessionUserService.Current == null)
{
filterContext.Result = new RedirectResult(Url.Action("SignIn", "Access", new { area = string.Empty }));
return;
}
}
}
}
自定义授权属性
public class AuthorizeByPermission : AuthorizeAttribute
{
public Permission[] Permissions { get; set; }
public AuthorizeByPermission(params Permission[] permissions)
{
this.Permissions = permissions;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
SessionUser sessionUser = filterContext.HttpContext.Session.Get<SessionUser>();
if (sessionUser.HasPermission(Permissions))
return;
filterContext.Result = new HttpUnauthorizedResult();
}
}
问题是 BaseController OnActionExecuting 方法在我的 AuthorizeByPermission 属性中的 OnAuthorization 方法之后触发,我需要它是另一种方式,因为 BaseController 需要填充 Session 变量(如果它在授权之前不存在)属性尝试访问它。
基本上,我需要找到一种方法来拥有可以在 OnAuthorization 方法触发之前注册的基类方法或全局过滤器。关于如何做到这一点有什么想法吗?
我尝试注册 GlobalFilter 来加载会话变量并将其 Order 属性设置为低于 AuthorizeByPermission 属性,但这似乎也不起作用。
我还尝试重写 BaseController 中的 Execute 方法,该方法实际上在自定义授权属性之前触发,但问题是我无权访问 filterContext,如果无法访问,该方法允许我将用户重定向到登录页面加载会话变量。
根据 bmosh 的评论,我尝试将 BaseController OnActionExecuting 方法转换为单独的过滤器,并使用该属性装饰 BaseController,该属性的订单号低于 AuthorizeByPermission 属性,但它仍然不起作用。
[FilterIWantToFireFirst(Order = 1)]
public class BaseController : Controller
{
}
public class AnotherController : BaseController
{
[AuthorizeByPermission(Permission.Add, Order = 2)]
public ActionResult SomeActionMethod()
{
}
}
即使采用上述设置,AuthorizeByPermission 属性也会首先被触发。
有什么想法吗?
In my application (ASP.NET MVC 3) I have a BaseController class that all my Controllers inherit and in that BaseController I have overridden the OnActionExecuting method to check to ensure a Session variable is populated as I need access to that in all other action methods in the application. I also have a custom Authorize attribute that I have defined that extends the AuthorizeAttributeClass. In that attribute I override OnAuthorization to check the same Session variable I am loading in the BaseController OnActionExecuting method to see if the user should be permitted to continue.
BaseController
public class BaseController : Controller
{
private ISessionUserService sessionUserService;
public BaseController(ISessionUserService sessionUserService)
{
this.sessionUserService = sessionUserService;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (User != null && User.Identity.IsAuthenticated && this.sessionUserService.Current == null)
{
this.sessionUserService.Start(accountID, User.Identity.Name);
// If we weren't successful in reloading the SessionUser
// variable, redirect the user to the Sign In view
if (this.sessionUserService.Current == null)
{
filterContext.Result = new RedirectResult(Url.Action("SignIn", "Access", new { area = string.Empty }));
return;
}
}
}
}
Custom Authorize Attribute
public class AuthorizeByPermission : AuthorizeAttribute
{
public Permission[] Permissions { get; set; }
public AuthorizeByPermission(params Permission[] permissions)
{
this.Permissions = permissions;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
SessionUser sessionUser = filterContext.HttpContext.Session.Get<SessionUser>();
if (sessionUser.HasPermission(Permissions))
return;
filterContext.Result = new HttpUnauthorizedResult();
}
}
The problem is that the BaseController OnActionExecuting method is firing AFTER the OnAuthorization method in my AuthorizeByPermission attribute and I need it to be the other way arround as the BaseController needs to popualte the Session variable if it isn't there before the authorize attribute attempts to access it.
Basically I need to find a way to have a base class method or a global filter that can be registered to occur before the OnAuthorization method fires. Any ideas on how to do this?
I have tried registering a GlobalFilter to load the session variable and set its Order property to be lower than the AuthorizeByPermission attribute but that didn't seem to work either.
I have also tried overriding the Execute method in the BaseController and that actually fired before the custom authorization attribute but the problem was that I didn't have access to the filterContext which allowed me to redirect the user to the SignIn page if we couldn't load the session variable.
As per bmosh's comment I tried turning my BaseController OnActionExecuting method into a separate filter and decorate the BaseController with that attribute with a lower Order number than the AuthorizeByPermission attribute but it still didn't work.
[FilterIWantToFireFirst(Order = 1)]
public class BaseController : Controller
{
}
public class AnotherController : BaseController
{
[AuthorizeByPermission(Permission.Add, Order = 2)]
public ActionResult SomeActionMethod()
{
}
}
Even with the above setup, the AuthorizeByPermission attribute is fired first.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以尝试在基本控制器中覆盖 OnAuthorization 而不是 OnActionExecuting 。
You could try overriding OnAuthorization instead of OnActionExecuting in your base controller.