C# ASP.Net MVC:可以覆盖 AuthorizeAttribute 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/532773/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.Net MVC: Can the AuthorizeAttribute be overriden?
提问by Keith Bloom
My current project is an internal web application built using ASP.Net MVC which I am adding authentication to. I have a pre-built HTTPModule which creates a IPrincipal with the appropriate roles. If the user isn't authenticated I get a user object with the role "Public"
我当前的项目是使用 ASP.Net MVC 构建的内部 Web 应用程序,我正在向其中添加身份验证。我有一个预先构建的 HTTPModule,它创建了一个具有适当角色的 IPrincipal。如果用户未通过身份验证,我会得到一个角色为“公共”的用户对象
As this is an internal application most of the pages are private and only viewable to the role "Admin". As I have a base controller I can do this:
由于这是一个内部应用程序,因此大多数页面都是私有的,并且只能由角色“管理员”查看。因为我有一个基本控制器,所以我可以这样做:
[Authorize(Roles="Admin")]
public abstract class MyControllerBase : Controller
{
...
}
I have a problem though as some of the actions are viewable on a public website and if I attribute them like so:
我有一个问题,因为某些操作可以在公共网站上查看,如果我将它们归为这样:
[Authorize(Roles="Public")]
public class LoginController : MyController
{
public ActionResult Index()
{
}
}
The page fails to load as the user isn't authenticated. It would seem the Role of "Public is being ignored on the inherited class. Does anyone know if the roles can be overridden by inherited classes?
由于用户未通过身份验证,因此页面无法加载。似乎“公共在继承的类上被忽略了。有谁知道这些角色是否可以被继承的类覆盖?
I am also trying to avoid attributing all the controllers with Roles="Admin"
我还试图避免将所有控制器归因于 Roles="Admin"
Thanks, Keith.
谢谢,基思。
采纳答案by Keith Bloom
Well in the end I think my answer was in the question. Instead of putting the Authorize attribute on my base controller I have derived a new AdminBaseController.
最后我想我的答案是在问题中。我没有将 Authorize 属性放在我的基本控制器上,而是派生了一个新的 AdminBaseController。
[HandleError]
public abstract class MyControllerBase : Controller
{
...
}
[Authorize(Roles="Admin")]
public abstract class AdminControllerBase : MyControllerBase
{
....
}
Now any controllers that require authentication can derive from AdminControllerBase while my public controllers can derive from MyControllerBase. OO to the rescue.
现在,任何需要身份验证的控制器都可以从 AdminControllerBase 派生,而我的公共控制器可以从 MyControllerBase 派生。OO救援。
回答by tvanfosson
You can derive a new attribute from AuthorizeAttribute and override the OnAuthorization method, then apply your customized attribute instead of Authorize. Below is the OnAuthorization method from one of my customized attributes that redirects to an error page if the privileges aren't sufficient instead of redirecting to the logon page.
您可以从 AuthorizeAttribute 派生一个新属性并覆盖 OnAuthorization 方法,然后应用您的自定义属性而不是 Authorize。下面是来自我的自定义属性之一的 OnAuthorization 方法,如果权限不足,则重定向到错误页面而不是重定向到登录页面。
I'm not sure exactly what this will buy you, though. When you decorate your class with the attribute, presumably you'll have to allow both Admin and Public (so who are you restricting since Public is anyone who is not authenticated?). You'd then have to decorate each of the controller methods that need to be restricted to Admin individually since the class attribute would allow access otherwise. You can achieve this behavior with the regular Authorize attribute by simply decorating just those non-publicly available methods (or classes that have no publicly available methods).
不过,我不确定这到底会给你带来什么。当你用属性装饰你的类时,大概你必须同时允许 Admin 和 Public(所以你限制谁,因为 Public 是任何未经身份验证的人?)。然后您必须装饰需要单独限制为 Admin 的每个控制器方法,因为 class 属性将允许访问。您可以使用常规 Authorize 属性通过仅修饰那些非公开可用的方法(或没有公开可用方法的类)来实现此行为。
I suppose you could have your attribute check to see if the method being called is also decorated with the attribute and simply approve the authorization, which would effectively defer the authorization to the method level. You'd probably have to peek into the RouteData on the AuthorizationContext to get the action and use reflection to try and find the appropriate method based on parameters and request type.
我想你可以检查你的属性,看看被调用的方法是否也用属性装饰,然后简单地批准授权,这将有效地将授权推迟到方法级别。您可能必须查看 AuthorizationContext 上的 RouteData 以获取操作并使用反射尝试根据参数和请求类型找到适当的方法。
public override void OnAuthorization( AuthorizationContext filterContext )
{
if (filterContext == null)
{
throw new ArgumentNullException( "filterContext" );
}
if (AuthorizeCore( filterContext.HttpContext ))
{
SetCachePolicy( filterContext );
}
else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
}
else
{
ViewDataDictionary viewData = new ViewDataDictionary();
viewData.Add( "Message", "You do not have sufficient privileges for this operation." );
filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
}
}
protected void SetCachePolicy( AuthorizationContext filterContext )
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge( new TimeSpan( 0 ) );
cachePolicy.AddValidationCallback( CacheValidateHandler, null /* data */);
}