ASP.NET MVC – 如何在login页面显示未经授权的错误?

在我的ASP.NET MVC应用程序中,我有大多数控制器装饰

[Authorize(Roles="SomeGroup")] 

当用户没有权限访问某些东西时,他们被发送到“〜/ Login”,这是我的账户控制器上的login操作。

我怎样才能确定一个用户已经到达login页面,因为没有被授权,以便我可以显示一个适当的错误?

您可以查找?ReturnUrl= querystring值,或者您可以创build您自己的授权筛选器并在TempData设置一个指示原因的字段。

这是一个简单的自定义filter,将做的伎俩:

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class CustomAuthorizeAttribute : AuthorizeAttribute { // NOTE: This is not thread safe, it is much better to store this // value in HttpContext.Items. See Ben Cull's answer below for an example. private bool _isAuthorized; protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) { _isAuthorized = base.AuthorizeCore(httpContext); return _isAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); if(!_isAuthorized) { filterContext.Controller.TempData.Add("RedirectReason", "Unauthorized"); } } } 

然后在你看来,你可以做这样的事情:

 @if(TempData["RedirectReason"] == "Unauthorized") { <b>You don't have permission to access that area</b> } 

(虽然我build议比这些魔术弦更好的方法,但你明白了)

更新(2015年6月): @ daniel-lidström已经正确地指出,你不应该在ASP.NET MVC应用程序中使用Response.Redirect。 有关为什么的更多信息,请参阅此链接: Response.Redirect和ASP.NET MVC – 不要混合 。

更新(2014年9月):我不知道何时将HandleUnauthorizedRequest添加到AuthorizeAttribute,但是无论哪种方式,我已经能够将AuthorizeRedirect代码细化到更小和更简单的代码中。

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AuthorizeRedirect : AuthorizeAttribute { public string RedirectUrl = "~/Error/Unauthorized"; protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.Result = new RedirectResult(RedirectUrl); } } } 

下面的原始答案(仍然function齐全)

我已经在这里留下了这个答案,因为它仍然让你了解授权pipe道的工作原理。

对于仍然在这里登陆的人,我已经编辑Ben Scheirman的答案,当用户login但未经授权时自动redirect到未经授权的页面。 您可以使用名称参数RedirectUrl更改redirectpath。

编辑:我已经使解决scheme线程安全感谢Tarynn和MSDN的build议

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AuthorizeRedirect : AuthorizeAttribute { private const string IS_AUTHORIZED = "isAuthorized"; public string RedirectUrl = "~/error/unauthorized"; protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) { bool isAuthorized = base.AuthorizeCore(httpContext); httpContext.Items.Add(IS_AUTHORIZED, isAuthorized); return isAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); var isAuthorized = filterContext.HttpContext.Items[IS_AUTHORIZED] != null ? Convert.ToBoolean(filterContext.HttpContext.Items[IS_AUTHORIZED]) : false; if (!isAuthorized && filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl); } } } 

Ben Cull的方法运行良好,但请记住有两个AuthorizeAttribute类 – 一个在System.Web.HTTP(由Web API使用)中,另一个在System.Web.Mvc中。 Ben的方法使用System.Web.Mvc类。 为了清楚起见,我build议使用完全合格的path。

如果您正在使用Web API和MVC,则需要实现两个filter:

 public class AuthorizeRedirectMVCAttribute : System.Web.Mvc.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { filterContext.Result = new RedirectResult("~/Account/AccessDenied"); } } } public class AuthorizeRedirectAPIAttribute : System.Web.Http.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { base.HandleUnauthorizedRequest(actionContext); if (actionContext.RequestContext.Principal.Identity.IsAuthenticated) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden); } } } 

请注意,asp.net将让你用APIfilter来装饰你的MVC控制器 – 它不会像你期望的那样工作,所以保持你的属性名称是明确的。

如果你有一个控制器,并且不想在你的代码中有一个url,你也可以用这个方法redirect。 它不会更改浏览器的地址栏中的url,以便用户永远不会看到未经授权的页面的url。 这是用MVC 3编写的。如果你想将它们redirect到一个login页面,或者你想把它们redirect到一个页面,告诉它们没有被授权,这个方法也可以工作。 我在程序中有一个部分,一些用户没有权限,但他们已经login,所以这就是我使用的。

 public class AuthorizedRedirect : AuthorizeAttribute { protected override bool AuthorizeCore(HttpContextBase httpContext) { bool isAuthorized = base.AuthorizeCore(httpContext); return isAuthorized; } protect override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.RequestContext.RouteData.Values["controller"] = "error"; filterContext.Result = new ViewResult { ViewName = "unauthorized" }; } 

而更简单的版本使用FormsAuthentication设置。 对于那些不熟悉Contract的人来说,Contract.Requires是一个.NET 4的补充。 利用代码合同的优点和缺点。

 public class RequiresAttribute : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { Contract.Requires(filterContext != null); HttpContextBase context = filterContext.RequestContext.HttpContext; if (context.User.Identity.IsAuthenticated) { // user does not possess the required role permission string url = context.GetCustomErrorUrl(401); context.Response.Redirect(url); } else { // redirect the user to the login page string extraQueryString = context.Request.RawUrl; FormsAuthentication.RedirectToLoginPage(extraQueryString); } } } 

即使你没有控制器,你仍然可以使用HandleUnauthorizedRequest来改变redirect。

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AuthoriseRedirect : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.RequestContext.HttpContext.Response.Redirect("UrlToRedirectTo"); } } 

如果你有一个遗留的webforms网站,你会转换到MVC更长的时间来得心应手…..!

我喜欢Brian Vander Plaats发布的内容,只是增加了一些改进:

 /// <summary> /// Authorize or redirect to an unauthorized MVC action if the user does not have the required roles /// (an unauthenticated user will be redirected to the defualt sign in action) /// <para>Decorate an action or a controller like this [AuthorizeAndRedirect(Roles = "RoleName")]</para> /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class AuthorizeOrRedirectAttribute : System.Web.Mvc.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated) { var routeData = new RouteData(); routeData.Values.Add("controller", "Error"); routeData.Values.Add("action", "Unauthorized"); filterContext.Result = new RedirectToRouteResult(routeData.Values); } } } /// <summary> /// Authorize or redirect to an unauthorized API action if the user does not have the required roles /// (an unauthenticated user will be redirected to the defualt sign in action) /// <para>Decorate an action or a controller like this [AuthorizeAndRedirect(Roles = "RoleName")]</para> /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class AuthorizeOrRedirectApiFilterAttribute : System.Web.Http.AuthorizeAttribute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { base.HandleUnauthorizedRequest(actionContext); if (actionContext.RequestContext.Principal.Identity.IsAuthenticated) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); } } }