AddJwtBearer OnAuthenticationFailed返回自定义错误

时间:2018-02-06 18:35:40

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

我正在使用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开发者工具报告

  

(失败)

error

状态和

  

无法加载响应数据

error

回应。

我也尝试过:

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

但结果是一样的。

所需行为
我想返回自定义状态代码,并显示错误信息。

4 个答案:

答案 0 :(得分: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;
                }
            };
        });

答案 1 :(得分:6)

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

enter image description here

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

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

答案 2 :(得分:0)

请检查.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;                        
                },

答案 3 :(得分:0)

这是在发现与更新包之后似乎出现的与该异常相关的问题之后对我有用的东西。

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