我正在设置一个测试项目来总体了解 OpenID Connect 和具体了解 OpenIddict。我在 ASP.NET Core 8 中设置了 3 个项目,一个 ResourceAPI、一个 AuthServer 和一个客户端 (Blazor)。它们都在本地运行,但在不同的端口上。
我想设置授权代码流程。我根据Balosar 示例在服务器和客户端中进行了适当的配置。 当运行客户端时,发生的第一件事是调用
.well-known/openid-configuration
端点,正如我所料。我收到响应,但由于缺少 CORS 标头,它被我的浏览器 (Brave) 阻止:
从源“https://localhost:7098”访问“https://localhost:7120/.well-known/openid-configuration”处的 XMLHttpRequest 已被 CORS 策略阻止:无“Access-Control-Allow-Origin” ' 标头存在于所请求的资源上。 确实没有 CORS 标头,并且该错误对我来说是有意义的,因为应用程序位于不同的端口上。
我在AuthServer中添加了CORS配置。 深入研究中间件的 OpenIddict 处理,我注意到除非我在配置中启用端点通过,否则不会运行其他中间件,包括 CORS 中间件。
因为没有配置可以让我在
.well-known/openid-configuration
端点上启用直通(即使实现了,我也不希望自己实现它)并且不知道如何继续。
我在 Chavlet 先生(OpenIddict 作者)关于类似问题的问题上找到了这个答案,这让我觉得我做错了什么,但我不知道是什么
您必须使用 CORS 作为授权端点的事实让我认为您做错了什么。
我是否缺少一些允许 OpenIddict 使用 CORS 的配置细节,或者我是否误解了流程?
这是我的 AuthServer 配置。请注意,授权代码流程尚未完全实现,我想在继续之前克服这个 CORS 障碍。 另请注意,我正在降级模式下运行,因为这就是我在真实代码库中设置后将使用的模式。
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddCors(opt => opt.AddPolicy("AllowThePlaygroundClient", policy => policy
.WithOrigins("https://localhost:7098")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials())
)
.AddOpenIddict()
.AddServer(opt =>
{
opt.EnableDegradedMode();
opt.AddEphemeralEncryptionKey();
opt.AddEphemeralSigningKey();
opt.DisableAccessTokenEncryption();
opt.AllowPasswordFlow();
opt.AllowAuthorizationCodeFlow();
opt.SetTokenEndpointUris("connect/token");
opt.AddEventHandler<ValidateTokenRequestContext>(builder => builder.UseInlineHandler(context =>
{
// TODO: Add validation logic
return default;
}));
opt.UseAspNetCore()
.EnableTokenEndpointPassthrough();
});
var app = builder.Build();
app.UseCors("AllowThePlaygroundClient");
app.MapPost("connect/token", (Delegate)((HttpContext context) =>
{
var request = context.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("Not a valid OIDC request");
if (request.IsPasswordGrantType())
{
// In a reald world scenario we should never tell why the authentication has failed
if (request.Username != _user.email || request.Password != _user.password)
{
return Task.FromResult(Results.NotFound("Invalid credentials!"));
}
var identity = new ClaimsIdentity(authenticationType: "jivete")
.SetClaim(Claims.Subject, _user.email)
.SetClaim(Claims.Name, _user.name)
.SetClaim(Claims.Email, _user.email);
identity.SetAudiences(new[] { "resourceApi" });
return Task.FromResult(Results.SignIn(new ClaimsPrincipal(identity), authenticationScheme: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
}
throw new InvalidOperationException("The specified grant type is not supported.");
}));
app.Run();
这是客户端的配置:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddOidcAuthentication(opt =>
{
opt.ProviderOptions.Authority = "https://localhost:7120";
opt.ProviderOptions.ClientId = "myClientId";
opt.ProviderOptions.ResponseType = "code";
opt.ProviderOptions.ResponseMode = "query";
opt.ProviderOptions.DefaultScopes.Add("roles");
opt.UserOptions.RoleClaim = "role";
});
await builder.Build().RunAsync();
要使此场景发挥作用,必须在身份验证中间件(负责调用 OpenIddict,以
IAuthenticationRequestHandler
的形式实现)启动之前调用 CORS 中间件。
当使用最小 Web 主机(即
WebApplication.CreateBuilder(args)
)时,身份验证中间件会在 ASP.NET 团队选择的位置为您注册,这不一定有效,具体取决于场景。
为了防止这种情况,请手动注册身份验证和授权中间件:
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors("AllowThePlaygroundClient");