AddJwtBearer OnAuthenticationFailed返回自定义错误

Mak*_*kla 2 asp.net-core openiddict asp.net-core-2.0

我正在使用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);
                    }
                };
            });
Run Code Online (Sandbox Code Playgroud)

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

(失败)

错误

状态和

无法加载响应数据

错误

回应.

我也尝试过:

context.Response.WriteAsync(result).Wait();
return Task.CompletedTask;
Run Code Online (Sandbox Code Playgroud)

但结果是一样的.

期望的行为:
我想返回自定义状态代码,其中包含错误信息.

小智 9

面对同样的问题,尝试了Pinpoint提供的解决方案,但它在ASP.NET核心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;
                }
            };
        });
Run Code Online (Sandbox Code Playgroud)


Tyl*_*r V 8

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

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)
Run Code Online (Sandbox Code Playgroud)

实施如下,

                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;
                }
Run Code Online (Sandbox Code Playgroud)


Kév*_*let 6

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

在此输入图像描述

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

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
            };

            return context.Response.WriteAsync(payload.ToString());
        };
    });
Run Code Online (Sandbox Code Playgroud)

  • `HandleResponse` 不返回任何内容(我同意这是一个糟糕的名字)。它只是告诉 JWT 处理程序您想要处理响应并且不希望应用默认逻辑(返回“WWW-Authenticate”标头)。 (2认同)
  • 如果没有 HandleResponse(),我会收到错误日志“System.InvalidOperationException:无法设置 StatusCode,因为响应已开始。”。通过添加它,我不再看到该错误。这条线对我真的很有帮助。谢谢。 (2认同)