我正在尝试在 .NET 8 Web API 中启用 OpenIdConnect 和 Cookie:
builder.Services
.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "MyPolicy";
options.DefaultAuthenticateScheme = "MyPolicy";
})
.AddCookie(options =>
{
// add an instance of the patched manager to the options:
options.CookieManager = new ChunkingCookieManager();
options.Cookie.HttpOnly = true;
options.Cookie.SameSite = SameSiteMode.None;
options.Cookie.SecurePolicy = CookieSecurePolicy.None;
})
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Authority = "";
options.ClientId = "";
options.ClientSecret = "";
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ResponseType = "code";
options.Prompt = "login";
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.RequireHttpsMetadata = false;
})
.AddJwtBearer(options =>
{
// some configuration
})
.AddPolicyScheme("MyPolicy", "My test Policy", options =>
{
options.ForwardDefaultSelector = context =>
{
// Decide which Authentication schema to use for each request
string authorization = context.Request.Headers[HeaderNames.Authorization];
if (authorization != null && authorization.StartsWith("Bearer", StringComparison.OrdinalIgnoreCase))
{
return BearerAuthenticationSchemeName;
}
if (context.Request.Path.StartsWithSegments("/swagger"))
{
return OpenIdConnectDefaults.AuthenticationScheme;
}
return CookieAuthenticationDefaults.AuthenticationScheme;
};
});
var app = builder.Build();
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.None,
Secure = CookieSecurePolicy.Always,
});
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI();
// more middleware
当我打开
/swagger
端点时,它会将我重定向到登录页面。我成功登录,然后将我重定向到 /signin-oidc
,这是预期的。然而,OpenIdConnectAuthenticationHandler
抛出了一个异常,指出message.State is null or empty
。
System.Exception: An error was encountered while handling the remote login.
---> System.Exception: OpenIdConnectAuthenticationHandler: message.State is null or empty.
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at MyApp.Middlewares.LoggingMiddleware.InvokeAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
当我在本地运行它时(例如在
http://localhost:5000/swagger
上),它工作得很好,但是当我在https://myexampleurl.whatever/swagger/
上打开它时,我得到了异常。我不知道为什么这不起作用,也不知道我在这里做错了什么。我看到 cookie 是以以下格式发送的:.AspNetCore.OpenIdConnect.Nonce.<somehugestring>; .AspNetCore.Correlation.<correlation>; <anotherbigstring>
,值得注意的是 Authority
和我的 myexampleurl
是不同的域。
还值得注意的是,当我在本地运行此程序并重定向到
/signin-oidc
时,浏览器确实会发送 4 个 cookie:2 个 AspNetCore.Correlation
和 2 个 AspNetCore.OpenIdConnect.Nonce
cookie,它们都具有不同的值。对于另一个,它根本不发送任何 cookie。
首先是我的 cookie 策略设置。当在
SameSite
中间件中将 None
属性设置为 app.UseCookiePolicy()
时,必须将 cookie 标记为安全(CookieSecurePolicy.Always
),否则浏览器将不会在后续请求中存储或发送它,这会导致HTTP 500
就我而言。然而,即使在引入了上述更改之后,我仍然遇到了麻烦。因此,在深入挖掘之后,我在 Auth0 上发现了一篇题为“ASP.NET Core 错误重定向 url”的论坛帖子,该帖子内部链接/导致 StackOverflow 上的另一篇帖子“AspNetCore Azure AD Connect 回调 URL 是 http,而不是 https” ”。最终,答案建议在应用程序的中间件中调用 app.UseForwardedHeaders()
之前添加 app.UseAuthentication()
。这样做之后(基本上遵循与帖子答案相同的逻辑),一切都开始正常工作。
所以,在一切都改变之后,这就是我的
Program.cs
:
builder.Services.AddAuthentication().AddCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SameSite = SameSiteMode.None;
options.Cookie.SecurePolicy = CookieSecurePolicy.None;
}).AddOpenIdConnect(...).AddJwtBearer(...).AddPolicyScheme(...);
var app = builder.Build();
ForwardedHeadersOptions forwardedHeadersOptions = new()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
};
forwardedHeadersOptions.KnownNetworks.Clear();
forwardedHeadersOptions.KnownProxies.Clear();
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.None,
Secure = CookieSecurePolicy.Always,
});
app.UseForwardedHeaders(forwardedHeadersOptions);
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI();
// more middleware