当用户在asp.net mvc3中未被授权时,重定向到另一个页面

23

我阅读了如何在MVC 3中轻松重定向未经身份验证的用户?当用户未被授权时重定向到AccessDenied页面,但是一个回答中的链接(即http://wekeroad.com/2008/03/12/aspnet-mvc-securing-your-controller-actions/)失效了。

我放置了

[Authorize(Users = "test")]
    public class RestrictedPageController: Controller
    {

        public ActionResult Index()
        {
           return View();
        }

 ....
    }

而且我在我的web.config文件中已经

 <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
 </authentication>

根据https://dev59.com/GWw15IYBdhLWcg3wMY6L#6770583的建议:

但是当我想要访问/RestrictedPage/Index时,它必须将我重定向到其他页面(来自其他控制器)。但实际上出现了错误提示:

Server Error in '/Project' Application.

The view 'LogOn' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Account/LogOn.aspx
~/Views/Account/LogOn.ascx
~/Views/Shared/LogOn.aspx
~/Views/Shared/LogOn.ascx
~/Views/Account/LogOn.cshtml
~/Views/Account/LogOn.vbhtml
~/Views/Shared/LogOn.cshtml
~/Views/Shared/LogOn.vbhtml

在登录之前,Logon 页面表单显示正确,但访问 /RestrictedPage/Index 页面时出现上述错误。我可以使用另一个被授权访问 RestrictedPage 页面的用户登录。

我的错误在哪里?如何设置重定向?

5个回答

66

默认的Authorize属性的行为是这样的,当用户未经过身份验证已经通过身份验证但未被授权时,它会将状态代码设置为401(未经授权)。当筛选器将状态代码设置为401时,ASP.NET框架检查网站是否启用了表单身份验证,并且如有,则重定向到在那里设置的loginUrl参数。

如果您想更改该行为,假设您想要在用户经过身份验证但未被授权时将其重定向到一个AccessDenied控制器,则必须扩展Authorize属性并覆盖HandleUnauthorizedRequest方法。

例如:

public class CustomAuthorize: AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
        else
        {
           filterContext.Result = new RedirectToRouteResult(new 
               RouteValueDictionary(new { controller = "AccessDenied" }));
        }
    }
}

您可以根据需要覆盖HandleUnauthorizedRequest,然后必须标记控制器操作以使用CustomAuthorize属性而不是内置的属性。


1
点赞并接受!一个注意事项:必须使用protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)来重写该方法,否则无法正常工作。 - Snake Eyes
1
这是我一直遇到的一个解决方案,但这真的还是唯一的方法吗?不得不重新创建[Authorize]过滤器只是为了更改路径似乎有些过度。 - Lukas
如果您想在整个项目中需要授权,则将以下行添加到AppStart/FilterConfig: filters.Add(new AuthorizeAttribute()); - Web Developer

7

我喜欢Mark的答案,但我不想改变所有的操作属性从[Authorize]到[CustomAuthorize]

我编辑了AccountController上的Login()操作,并在显示视图之前检查Request.IsAuthenticated。如果经过身份验证的用户转到/Account/Logon,我将重定向到/Error/AccessDenied。

    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        if (Request.IsAuthenticated)
        {
            return RedirectToAction("AccessDenied", "Error");
        }

        ViewBag.ReturnUrl = returnUrl;

        return View();
    }

但是在这种情况下,如果您已经登录并转到登录页面,您将看到一个/error/accessDenied而不是/account/login,对吗?如果您不想将[Authorize]更改为[CustomAuthorize],您可以将其命名为YourBrand.YourProject.Security.AuthorizeAttribute,然后仅引用YourBrand.YourProject.Security或其他内容。 - percebus
1
我喜欢这个解决方案,但如果他们已经通过身份验证但未被授权,则会重定向到一个非错误的主页,其中每个人都被授权,并包括一个可选的ViewBag状态消息,例如 $"您未被授权查看{returnUrl}"。 - reasonet

3

由于我不想覆盖AuthorizeAttribute,所以我使用了过滤器。

public class RedirectFilter : ActionFilterAttribute
{
   public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

        if (!IsAuthorized(filterContext))
        {
            filterContext.Result =
                new RedirectToRouteResult(new RouteValueDictionary(new {controller = "AccessDenied"}));
        }
    }

    private bool IsAuthorized(ActionExecutingContext filterContext)
    {
        var descriptor = filterContext.ActionDescriptor;
        var authorizeAttr = descriptor.GetCustomAttributes(typeof(AuthorizeAttribute), false).FirstOrDefault() as AuthorizeAttribute;

        if (authorizeAttr != null)
        {
            if(!authorizeAttr.Users.Contains(filterContext.HttpContext.User.ToString()))
            return false;
        }
        return true;

    }
}

2

使用“/Account/LogOn”代替“~/Account/LogOn”


1

是的,在 web.config 中你提到的是正确的。

<forms loginUrl="~/Account/LogOn" timeout="2880" />

重定向正在寻找帐户控制器和LogOn ActionResult。如果您想要重定向您的页面,请在那里更改,而不是在帐户和登录中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接