【问题标题】:AddJwtBearer OnAuthenticationFailed return custom errorAddJwtBearer OnAuthenticationFailed 返回自定义错误
【发布时间】:2018-07-16 21:52:45
【问题描述】:

我正在使用Openidict
我正在尝试使用自定义状态代码返回自定义消息,但我无法做到。我在startup.cs中的配置:

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(o =>
            {
                o.Authority = this.Configuration["Authentication:OpenIddict:Authority"];
                o.Audience = "MyApp";           //Also in Auhorization.cs controller.
                o.RequireHttpsMetadata = !this.Environment.IsDevelopment();
                o.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = context =>
                    {
                        context.Response.StatusCode = HttpStatusCodes.AuthenticationFailed;
                        context.Response.ContentType = "application/json";
                        var err = this.Environment.IsDevelopment() ? context.Exception.ToString() : "An error occurred processing your authentication.";
                        var result = JsonConvert.SerializeObject(new {err});
                        return context.Response.WriteAsync(result);
                    }
                };
            });

但问题是没有返回内容。 Chrome 开发者工具报告

(失败)

对于状态和

加载响应数据失败

响应。

我也试过了:

context.Response.WriteAsync(result).Wait();
return Task.CompletedTask;

但结果是一样的。

期望的行为:
我想返回自定义状态代码并显示出了什么问题。

【问题讨论】:

  • Do not post images of code or errors! 图片和屏幕截图可以很好地添加到帖子中,但请确保帖子在没有它们的情况下仍然清晰有用。如果您发布代码或错误消息的图像,请确保您还复制并粘贴或直接在帖子中输入实际代码/消息。
  • 无法加载vendor.js。你在Startup.cs 文件中使用app.UseStaticFiles() 吗?如果有,必须在app.UseAuthentication()之前注册。
  • OnAuthenticationFailed for JwtBearer 在 2.0 中无法再返回内容。它没有必要控制请求流。
  • @Rob 明白,我不确定文字是否足够。状态码失败对我来说真的很奇怪,虽然我发现返回的是实际代码,但是在 Angular 进程请求之后,代码被更改为失败。
  • @Brad 我正在使用UseStaticFiles,它在UseAuthentication 之前注册。它不是无法加载vendor,而是从vendor 引发错误。

标签: asp.net-core asp.net-core-2.0 openiddict


【解决方案1】:

遇到同样的问题,尝试了 Pinpoint 提供的解决方案,但它在 ASP.NET core 2.0 上对我不起作用。但是基于 Pinpoint 的解决方案和一些试验和错误,以下代码对我有用。

var builder = services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(o =>
        {
            o.Authority = "http://192.168.0.110/auth/realms/demo";
            o.Audience = "demo-app";
            o.RequireHttpsMetadata = false;

            o.Events = new JwtBearerEvents()
            {
                OnAuthenticationFailed = c =>
                {
                    c.NoResult();
                    c.Response.StatusCode = 500;
                    c.Response.ContentType = "text/plain";
                    c.Response.WriteAsync(c.Exception.ToString()).Wait();
                    return Task.CompletedTask;
                },
                OnChallenge = c =>
                {
                    c.HandleResponse();
                    return Task.CompletedTask;
                }
            };
        });

【讨论】:

    【解决方案2】:

    请务必注意,当返回 401 响应时,aspnet-contrib OAuth2 验证和 MSFT JWT 处理程序都会自动返回包含错误代码/描述的 WWW-Authenticate 响应标头:

    如果您认为标准行为不够方便,您可以使用事件模型手动处理挑战。例如:

    services.AddAuthentication()
        .AddJwtBearer(options =>
        {
            options.Authority = "http://localhost:54540/";
            options.Audience = "resource_server";
            options.RequireHttpsMetadata = false;
            options.Events = new JwtBearerEvents();
            options.Events.OnChallenge = context =>
            {
                // Skip the default logic.
                context.HandleResponse();
    
                var payload = new JObject
                {
                    ["error"] = context.Error,
                    ["error_description"] = context.ErrorDescription,
                    ["error_uri"] = context.ErrorUri
                };
    
                context.Response.ContentType = "application/json";
                context.Response.StatusCode = 401;
    
                return context.Response.WriteAsync(payload.ToString());
            };
        });
    

    【讨论】:

    • 我如何知道是否有错误? HandleResponse 是否返回任何有用的信息?
    • HandleResponse 不返回任何内容(我同意这是一个糟糕的名字)。它只是告诉 JWT 处理程序您要处理响应并且不希望应用默认逻辑(返回 WWW-Authenticate 标头)。
    • 如果没有 HandleResponse(),我会收到错误日志“System.InvalidOperationException:无法设置 StatusCode,因为响应已经开始。”。通过添加它,我不再看到该错误。那条线对我真的很有帮助。谢谢。
    • @KévinChalet 感谢您的回答,有没有办法返回 json 而不是文本?
    • @yavg 只需确保您返回带有application/jsonContent-Type 标头。我更新了我的答案以反映这一点。
    【解决方案3】:

    在发现与更新软件包后似乎出现的此异常相关的问题后,这对我有用。

    System.InvalidOperationException: StatusCode cannot be set because the response has already started.
       at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value)
       at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 value)
       at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32 value)
       at Microsoft.AspNetCore.Http.DefaultHttpResponse.set_StatusCode(Int32 value)
    

    实现如下,

                    OnAuthenticationFailed = context =>
                    {
                        context.NoResult();
                        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                        context.Response.ContentType = "application/json";
    
                        string response =
                            JsonConvert.SerializeObject("The access token provided is not valid.");
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                            response =
                                JsonConvert.SerializeObject("The access token provided has expired.");
                        }
    
                        context.Response.WriteAsync(response);
                        return Task.CompletedTask;
                    },
                    OnChallenge = context =>
                    {
                        context.HandleResponse();
                        return Task.CompletedTask;
                    }
    

    【讨论】:

      【解决方案4】:

      请查看 .net core 2.1 的波纹管代码

      OnAuthenticationFailed =context =>
                      {
                          context.Response.OnStarting(async () =>
                          {
                              context.NoResult();
                              context.Response.Headers.Add("Token-Expired", "true");
                              context.Response.ContentType = "text/plain";
                              context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                              await context.Response.WriteAsync("Un-Authorized");
                          });
      
                          return Task.CompletedTask;                        
                      },
      

      【讨论】:

        猜你喜欢
        • 2019-09-18
        • 2013-07-26
        • 2023-03-18
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-08
        • 2013-03-21
        相关资源
        最近更新 更多