因此,我使用.Net核心6和Keycloak,我想实现JWT授权。
我一直在遵循本教程,它是为.Net 5编写的,但我正在将它改编为.Net 6:
所以,我加入了这门课:
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
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();
在控制器上方:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
我使用的是Microsoft.AspNetCore.Authentication.JwtBearer 6.0.8。
现在,在这些设置之后,当我使用有效的令牌执行GET请求时,会得到:
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)
我不知道为什么。
有人知道为什么会发生这种事吗?我该怎么解决呢?
谢谢。
发布于 2022-08-27 17:47:45
错误消息是,其他组件已经将响应写入客户端。如果发生这种情况,您就不能再更改状态代码(这将是毫无意义的)。
您可以通过在管道开始时添加这样的中间件并在调试器下运行应用程序来了解写入响应的内容:
app.Use((context, next) =>
{
context.Response.OnStarting(() =>
{
Debugger.Break();
return Task.CompletedTask;
});
return next();
});
然后,您应该能够查看调用堆栈,并查看哪个组件正在写入响应。
https://stackoverflow.com/questions/73512387
复制相似问题