ASP.NET MVC使用自定义角色提供程序重定向到访问被拒绝页面

31

我正在创建一个自定义角色提供程序,并在我的控制器中设置了一个指定角色的Authorize属性,它可以正常工作,就像这样:

[Authorize(Roles="SuperAdmin")]
public class SuperAdminController : Controller
...

但是当用户没有访问该控制器的权限时,他将被重定向到登录页面。如何将其重定向到 "AcessDenied.aspx" 页面?

9个回答

43
[AccessDeniedAuthorize(Roles="SuperAdmin")]
public class SuperAdminController : Controller

AccessDeniedAuthorizeAttribute.cs:

public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if(filterContext.Result is HttpUnauthorizedResult)
        {
            filterContext.Result = new RedirectResult("~/AcessDenied.aspx");
        }
    }
}

7
如果用户已登录并尝试访问页面,则会被重定向到AccessDenied页面。好的。但是,如果用户未登录,则会被重定向到AccessDenied页面。这很糟糕。在这种情况下,他们应该被重定向到登录页面。 - Matt Frear
3
如果你希望在用户不再处于页面时正常重定向,可以在调用 base.OnAuthorization() 方法后,添加一个 if 语句来包围其他代码,检查 Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated。这样,除非用户未经身份验证,否则将重定向到 AccessDenied 页面...否则它将执行默认操作(重定向到登录页面)。 - Frinavale
这个类应该放在哪里?放在控制器里吗? - Jay
工作得很好,但我认为Frinavale的观点很好且有道理。 (y) - Fahad Mahmood
MVC:AcessDenied.aspx?不是cshtml? - Kiquenet

27

以下是基于eu-ge-ne的答案的解决方案。 我的解决方案能够正确地将用户重定向到登录页面,如果他们没有登录,但如果用户已经登录但未被授权查看该页面,则会将其重定向到拒绝访问页面。

[AccessDeniedAuthorize(Roles="SuperAdmin")]
public class SuperAdminController : Controller

AccessDeniedAuthorizeAttribute.cs:

public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            filterContext.Result = new RedirectResult("~/Account/Logon");
            return;
        }

        if (filterContext.Result is HttpUnauthorizedResult)
        {
            filterContext.Result = new RedirectResult("~/Account/Denied");
        }
    }
}

AccountController.cs:

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

Views/Account/Denied.cshtml: (Razor syntax)

@{
    ViewBag.Title = "Access Denied";
}

<h2>@ViewBag.Title</h2>

Sorry, but you don't have access to that page.

有任何“AccessDeniedForMobileOrTabletAttribute”吗? - Kiquenet

8
请看与此类似问题的链接,其中包含了tvanfosson答案。感谢tvanfosson的帮助,现在我只需要这样说:
[MyAuthorize(Roles="SuperAdmin",ViewName="AccessDenied")]
public class SuperAdminController : Controller
...

如果用户不在角色中,则会获得由 ViewName 指定的视图。

6

重定向并不总是最好的解决方案

使用标准的http代码 403:

return new HttpStatusCodeResult(HttpStatusCode.Forbidden);

6
通过避免硬编码登录页面并可选地在属性中设置拒绝访问视图,对Matt的回答进行了轻微的改进:
public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
    public string AccessDeniedViewName { get; set; }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated &&
            filterContext.Result is HttpUnauthorizedResult)
        {
            if (string.IsNullOrWhiteSpace(AccessDeniedViewName))
                AccessDeniedViewName = "~/Account/AccessDenied";

            filterContext.Result = new RedirectResult(AccessDeniedViewName);
        }
    }
}

1
我遇到了类似的问题。无论我使用什么角色,我总是被重定向到登录页面而不是AccessDenied页面。 修复方法非常简单,但可能并不适用于所有情况。原来,在Startup.cs文件中这两行代码的顺序错了:
app.UseAuthentication();
app.UseAuthorization();

确保在使用 app.UseAuthorization(); 前先使用 app.UseAuthentication();

换句话说,先问“你是谁?”,然后再问“你有权在这里吗?”,而不是反过来。


0

关于Vic Alcazar的一个小更新, 在重定向中添加了请求URL的详细信息 这样就可以记录访问被拒绝的详细信息和访问者身份(如果需要)

public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
    public string AccessDeniedViewName { get; set; }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated &&
            filterContext.Result is HttpUnauthorizedResult)
        {
            if (string.IsNullOrWhiteSpace(AccessDeniedViewName))
                AccessDeniedViewName = "~/Account/AccessDenied";

            var requestUrl = filterContext.HttpContext.Request.Url;

            filterContext.Result = new RedirectResult(String.Format("{0}?RequestUrl={1}", AccessDeniedViewName, requestUrl));
        }
    }
}

0

我在Vic的答案基础上进行了改进,使得我可以为每个应用程序区域设置不同的Access Denied页面。这是通过返回一个RedirectToRouteResult实现的,该结果不会将重定向到与应用程序根路径相关的URL,而是将其重定向到当前区域的控制器和操作:

public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
    public string AccessDeniedController { get; set; }
    public string AccessDeniedAction { get; set; }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated &&
            filterContext.Result is HttpUnauthorizedResult)
        {
            if (String.IsNullOrWhiteSpace(AccessDeniedController) || String.IsNullOrWhiteSpace(AccessDeniedAction))
            {
                AccessDeniedController = "Home";
                AccessDeniedAction = "AccessDenied";
            }

            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { Controller = AccessDeniedController, Action = AccessDeniedAction }));
        }
    }
}

0
public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);

            if (filterContext.Result is HttpUnauthorizedResult && WebSecurity.IsAuthenticated)
            {
                filterContext.Result = new RedirectResult("~/Account/AccessDenied");
            }
        }
    }

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