4

使用使用 .NET 4.5 和 IIS 8 的 MVC4 应用程序。当权限检查失败时,有没有办法返回自定义未经授权的页面和 401 结果?

我也在使用表单身份验证,并希望在用户未登录时重定向到登录页面,但在用户没有有效权限(即管理员)时重定向到未经授权的页面。

我还必须小心重定向,然后在成功重定向时获得 200/301 结果。

我需要返回 401 状态码并停留在当前页面,同时还返回自定义的未经授权的页面。

我有一个返回未经授权的视图的错误控制器:

[ActionName("unauthorised")]
    public ActionResult Http401() {
      Response.StatusCode = 401;
      Response.StatusDescription = "Unauthorised";
      Response.SuppressFormsAuthenticationRedirect = true;
      return View("unauthorised");
    }

如果权限检查失败,我有一些方法可以尝试调用 401:

/// <summary>Method to invoke when user attempts action without relevant permission</summary>
    /// <param name="httpContext">the httpcontext</param>
    /// <returns>empty result</returns>
    public ActionResult InvokeHttp401(HttpContextBase httpContext) {
      Transfer("/error/unauthorised");
      return new EmptyResult();
    }

    private void Transfer(string url) {
      var uriBuilder = new UriBuilder(Request.Url.Scheme, Request.Url.Host,    Request.Url.Port, Request.ApplicationPath); // Create URI builder
      uriBuilder.Path += url; // Add destination URI
      string path = Server.UrlDecode(uriBuilder.Uri.PathAndQuery); // Because UriBuilder escapes URI decode before passing as an argument
      this.HttpContext.RewritePath(path, false); // Rewrite path
      HttpContext.Server.TransferRequest(path, true);
    }

注意:我正在使用 Server.TransferRequest 以便我可以尝试在当前 url 上返回 401 结果,而不会导致任何重定向。我正在检查常规 ActionResult 中的权限,如下所示:

[Authorize]
public ActionResult MyMethod() {
  if (!UserHasPermission(Admin))
    return InvokeHttp401(HttpContext);
    ......

如果用户未登录,授权标签将重定向到登录,其他权限检查。

通过上述设置,我能够返回 401 结果并停留在当前 url,但显示的是 IIS 401 错误而不是我的当前页面。

我还尝试在我的 web.config 文件中设置以下内容:

<httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace">
      .....
      <error statusCode="401" responseMode="ExecuteURL" path="/Error/unauthorised" />
    </httpErrors>

但这没有什么区别。如果我没有在我的 Http401 ActionResult 中设置状态代码,我可以让自定义未经授权的页面出现,但它只是返回 200 结果。

我已经查看了关于这个问题的帖子(特别是 Timothy 的答案,它扩展了授权标签),但是如果没有已经描述的类似错误,就无法完成任何工作。

有人可以在这里帮忙吗?

4

1 回答 1

3

终于想通了——

使用 Timothy 在链接问题中建议的自定义授权标签和此博客文章的组合,我可以将状态代码临时设置为 418,然后在 Global.End_Request 中将其更改回 401。

我必须做的最后一件事是将 418 添加到我的 web.config 并使用PassThrough模式:

<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough">
      <remove statusCode="404" />
      <error statusCode="404" responseMode="ExecuteURL" path="/Error/not-found" />
      <remove statusCode="500" />
      <error statusCode="500" responseMode="ExecuteURL" path="/Error/error" />
      <remove statusCode="401" />
      <error statusCode="401" responseMode="ExecuteURL" path="/Error/unauthorised" />
    </httpErrors>

我在同一个 url 上得到了 401 结果,以及我的自定义视图。

于 2013-09-02T12:33:35.283 回答