如何使授权属性返回自定义的403错误页面,而不是重定向到登录页面

10 浏览
0 Comments

如何使授权属性返回自定义的403错误页面,而不是重定向到登录页面

[Authorize]属性是一个方便的微软发明,我希望它能解决我现在的问题。

更具体地说:

当当前客户端未经身份验证时,[Authorize]会将安全操作重定向到登录页面,登录成功后会将用户带回,这很好。

但是,当当前客户端已经通过身份验证但没有权限运行特定操作时,我只需要显示我通用的403页面。

在不将授权逻辑移动到控制器中的情况下,是否可能实现?

更新

我需要的行为应该在语义上等同于这个草图:

public ActionResult DoWork()
{
    if (!NotAuthorized())
    {
        // 这里不应该是重定向,而是转发
        return RedirectToAction("403");         
    }
    return View();
}

所以 - 不应该有任何重定向,URL应该保持不变,但页面的内容应该替换为403页面。

更新2:我以这种方式实现了草图:

[HandleError]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewData["Message"] = "欢迎使用ASP.NET MVC!";
        return View();
    }
    [CustomActionFilter]
    public ActionResult About()
    {
        return View();
    }
    public ActionResult Error_403()
    {
        return Content("403");
    }
}
public class CustomActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Result = new ContentResult { Content = "403" };
    }
}

但我不知道如何正确地将执行转发到HomeController.Action_403(),以便显示403。

更新3

filterContext.Result = new ViewResult() { ViewName = "Error_403" };

这是如何渲染特定视图模板的答案...但我仍然不知道如何运行另一个控制器 - 无论如何,这已经是一个足够好的解决方案。

0
0 Comments

问题的原因是默认的AuthorizeAttribute返回的是一个重定向到登录页面的结果,而不是返回一个自定义的403错误页面。解决方法是创建一个自定义的类,继承自AuthorizeAttribute,并重写AuthorizeCore方法,提供自己的授权机制。如果需要更精细的控制授权过程,可以实现IActionFilter接口,并在方法中提供替代行为。这可以通过实现OnActionExecuting方法来实现,在该方法中,可以根据逻辑决定是否调用控制器,以及提供一个替代的ActionResult。

为了返回一个403错误代码,不能使用ContentResult类,需要创建一个自定义的类,继承自ActionResult,并重写ExecuteResult方法,在该方法中设置HttpResponseBase的StatusCode属性为403。可以将Http403Result类进行泛化,接受一个构造函数参数,用于指定要返回的状态码,但概念保持不变。

在回答中还提到了一个问题,即在Web.config中启用customErrors时,是否可以正常工作。根据经验来看,可能不能正常工作,但没有确切的答案。

以下是整理后的文章:

你应该可以创建一个自己的类,该类派生自AuthorizeAttribute,并重写AuthorizeCore方法,以提供你想要的授权机制,这样你就可以使用属性应用你的自定义授权代码,而不是将其移到控制器中。

如果你需要更精细的控制授权,那么我建议你创建一个实现IActionFilter接口的实现(将其作为一个属性应用到你的方法中)。这将允许你在调用控制器之前拦截调用,并在调用控制器方法之前提供替代操作。

这通过在IActionFilter接口上实现OnActionExecuting方法来实现。如果你的逻辑确定根本不应该调用控制器,并且你想提供一个要处理的ActionResult,那么你可以在传入该方法的ActionExecutingContext实例上设置Result属性。通过这样做,该ActionResult将被处理,而不是转到控制器方法获取ActionResult。

如果你想返回一个403错误代码,那么就不能使用ContentResult类。你需要创建一个自己的类,该类派生自ActionResult,并重写ExecuteResult方法,将HttpResponseBase的StatusCode属性设置为403,如下所示:

internal class Http403Result : ActionResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        // Set the response code to 403.
        context.HttpContext.Response.StatusCode = 403;
    }
}
public class CustomActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Result = new Http403Result();
    }
}

当然,你可以将Http403Result类泛化,以接受一个构造函数参数,用于指定要返回的状态码,但概念是相同的。

在回答中还提到了一个问题,即在Web.config中启用customErrors时,是否可以正常工作。根据经验来看,可能不能正常工作,但没有确切的答案。

0
0 Comments

问题的原因是,Authorize属性默认情况下会将未授权的用户重定向到登录页面,而不是返回自定义的403错误页面。解决方法是创建一个自定义的Authorize属性子类,重写其HandleUnauthorizedRequest方法,使其在用户已经通过身份验证的情况下返回403状态码。然后,在Web.Config中添加system.webServer\httpErrors部分,将默认的403错误替换为自定义页面。

以下是解决方法的具体代码和配置:

public class MyAuthorizeAttribute : AuthorizeAttribute {
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
            filterContext.Result = new HttpStatusCodeResult(403);
        else
            filterContext.Result = new HttpUnauthorizedResult();
    } 
}


  
    
      
      
    
  

另外,如果想要获取自定义错误403页面/视图中的状态描述,可以使用以下代码:

@{
    var statusDescription = Response.StatusDescription;
}

以上就是解决问题的方法。

0