首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >由于响应已经启动,因此无法设置使用Keycloak ASP.Net StatusCode的JWT承载器身份验证。

由于响应已经启动,因此无法设置使用Keycloak ASP.Net StatusCode的JWT承载器身份验证。
EN

Stack Overflow用户
提问于 2022-08-27 15:46:50
回答 1查看 79关注 0票数 1

因此,我使用.Net核心6和Keycloak,我想实现JWT授权。

我一直在遵循本教程,它是为.Net 5编写的,但我正在将它改编为.Net 6:

https://blog.devgenius.io/security-in-react-and-webapi-in-asp-net-core-c-with-authentification-and-authorization-by-keycloak-f890d340d093

所以,我加入了这门课:

代码语言:javascript
运行
复制
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace mediere_API.Authorization
{
    public static class ConfigureAuthentificationServiceExtensions
    {
        private static RsaSecurityKey BuildRSAKey(string publicKeyJWT)
        {
            RSA rsa = RSA.Create();

            rsa.ImportSubjectPublicKeyInfo(

                source: Convert.FromBase64String(publicKeyJWT),
                bytesRead: out _
            );

            var IssuerSigningKey = new RsaSecurityKey(rsa);

            return IssuerSigningKey;
        }

        public static void ConfigureJWT(this IServiceCollection services, bool IsDevelopment, string publicKeyJWT)
        {
            var AuthenticationBuilder = services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            });

            AuthenticationBuilder.AddJwtBearer(o =>
              {

                  o.TokenValidationParameters = new TokenValidationParameters
                  {
                      ValidateAudience = false,
                      ValidateIssuer = true,
                      ValidIssuers = new[] { "http://localhost:8080/realms/MyRealm" },
                      ValidateIssuerSigningKey = true,
                      IssuerSigningKey = BuildRSAKey(publicKeyJWT),
                      ValidateLifetime = true
                  };

                  o.Events = new JwtBearerEvents()
                  {
                      OnTokenValidated = c =>
                      {
                          Console.WriteLine("User successfully authenticated");
                          return Task.CompletedTask;
                      },
                      OnAuthenticationFailed = c =>
                      {
                          c.NoResult();

                          c.Response.StatusCode = 500;
                          c.Response.ContentType = "text/plain";

                          if (IsDevelopment)
                          {
                              return c.Response.WriteAsync(c.Exception.ToString());
                          }
                          return c.Response.WriteAsync("An error occured processing your authentication.");
                      }
                  };

              });
        }
    }
}

还有我的Program.cs

代码语言:javascript
运行
复制
using mediere_API.Authorization;
using mediere_API.DataLayer;
using mediere_API.DataLayer.Repository.Implementations;
using mediere_API.DataLayer.Repository.Interfaces;
using mediere_API.Processors.Implementations;
using mediere_API.Processors.Interfaces;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

//Servicii
builder.Services.AddRouting(options => options.LowercaseUrls = true);
builder.Services.ConfigureJWT(true, "SECRET");
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

//CORS
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        policy =>
        {
            policy.AllowAnyOrigin()
                .AllowAnyHeader()
                .AllowAnyMethod();
        });
});


var connectionString = builder.Configuration.GetConnectionString("Postgres");
builder.Services.AddDbContext<EfDbContext>(options => options.UseNpgsql(connectionString));


var app = builder.Build();
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseCors();

app.MapControllers();

app.UseAuthorization();

app.Run();

在控制器上方:

代码语言:javascript
运行
复制
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

我使用的是Microsoft.AspNetCore.Authentication.JwtBearer 6.0.8。

现在,在这些设置之后,当我使用有效的令牌执行GET请求时,会得到:

代码语言:javascript
运行
复制
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      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)
         at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleChallengeAsync(AuthenticationProperties properties)
         at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.ChallengeAsync(AuthenticationProperties properties)
         at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
         at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
         at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

我不知道为什么。

有人知道为什么会发生这种事吗?我该怎么解决呢?

谢谢。

EN

回答 1

Stack Overflow用户

发布于 2022-08-27 17:47:45

错误消息是,其他组件已经将响应写入客户端。如果发生这种情况,您就不能再更改状态代码(这将是毫无意义的)。

您可以通过在管道开始时添加这样的中间件并在调试器下运行应用程序来了解写入响应的内容:

代码语言:javascript
运行
复制
app.Use((context, next) =>
{
    context.Response.OnStarting(() =>
    {
        Debugger.Break();
        return Task.CompletedTask;
    });

    return next();
});

然后,您应该能够查看调用堆栈,并查看哪个组件正在写入响应。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73512387

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档