【问题标题】:How to get statuscode in httpcontext after being redirected by AuthenticationHandler in MVC Core在 MVC Core 中被 AuthenticationHandler 重定向后如何在 httpcontext 中获取状态码
【发布时间】:2018-07-16 18:47:43
【问题描述】:

我一直在使用CookieAuthenticationHandler,但通过访问由具有Authorize 属性的控制器方法处理的视图而未能获得授权。

CookieAuthenticationHandler 然后将我重定向到HandleForbiddenAsyncHandleChallengeAsync 中的可配置路径(取决于它是身份验证还是授权)。但是,在重定向后,我注意到 HTTP 状态码丢失了。

我在控制器动作中添加了一个断点,该动作被重定向到,状态码为 200。

我期待一个不同的状态码(401 或 403)。


这就是HandleForbiddenAsync 中发生的事情(来自github):

protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
{
    var returnUrl = properties.RedirectUri;
    if (string.IsNullOrEmpty(returnUrl))
    {
        returnUrl = OriginalPathBase + Request.Path + Request.QueryString;
    }
    var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl);
    var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(accessDeniedUri));
    await Events.RedirectToAccessDenied(redirectContext);
}

所以我实现了自己的HandleForbiddenAsync(使用扩展CookieAuthenticationHandler的自定义AuthenticationHandler),并尝试通过添加以下行直接设置状态码:

redirectContext.Response.StatusCode = StatusCodes.Status403Forbidden;

但是当我到达断点时,我仍然看到状态码 200。

我很可能以错误的方式处理事情。我想要完成的是在我的索引视图的控制器中获得不同的状态码。

有什么想法吗?

【问题讨论】:

  • 我认为您可以通过简单的方式实现您想要的结果。当用户身份验证失败时,尝试在登录操作中返回 ForBidden()

标签: c# controller asp.net-core-mvc http-status-codes


【解决方案1】:

我已经深入研究了源代码并弄清楚了发生了什么。

Events.RedirectToAccessDenied(redirectContext); 中的状态码发生变化

它从 CookieAuthenticationEvents (github link) 开始

public virtual Task RedirectToAccessDenied(RedirectContext<CookieAuthenticationOptions> context)
    => OnRedirectToAccessDenied(context);

进入

public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToAccessDenied { get; set; }
    = context =>
{
    if (IsAjaxRequest(context.Request))
    {
        context.Response.Headers["Location"] = context.RedirectUri;
        context.Response.StatusCode = 403;
    }
    else
    {
        context.Response.Redirect(context.RedirectUri);
    }
    return Task.CompletedTask;
};

然后调用抽象HttpResponse 类(github link here) 的Redirect 方法,在这种情况下使用DefaultHttpResponse 实现,即

public override void Redirect(string location, bool permanent)
{
    if (permanent)
    {
        HttpResponseFeature.StatusCode = 301;
    }
    else
    {
        HttpResponseFeature.StatusCode = 302;
    }

    Headers[HeaderNames.Location] = location;
}

所以这里的状态码被改变了,重定向状态码被MVC拾取并变成了200。

如果只需在HandleChallengeAsyncHandleForbiddenAsync 方法中执行以下操作即可消除所有这些...

var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri("whatever"));
redirectContext.Response.Headers["Location"] = redirectContext.RedirectUri;
redirectContext.Response.StatusCode = 403;
await Task.CompletedTask;

...那么最终会发送正确的状态码。但是,它现在会被浏览器而不是 MVC 拾取,所以即使状态码现在终于出现了,浏览器也会给出一个默认的浏览器错误页面,仅此而已。


因为我想做的是进入我的重定向页面并显示一条消息,所以我决定只在查询字符串中添加状态码。这是我最后的HandleChallengeAsync

var unauthorizedUri = Options.LoginPath + QueryString.Create("error", "401");
var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(unauthorizedUri));
await Events.RedirectToLogin(redirectContext);

然后在控制器或视图中我可以简单地检查查询字符串。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 2018-02-14
    • 1970-01-01
    • 2019-05-11
    • 1970-01-01
    相关资源
    最近更新 更多