.NET 5 Blazor 服务器 OKTA 身份验证显示 HTTP 错误 400
Posted
技术标签:
【中文标题】.NET 5 Blazor 服务器 OKTA 身份验证显示 HTTP 错误 400【英文标题】:.NET 5 Blazor Server OKTA Authentication showing HTTP Error 400 【发布时间】:2022-01-21 10:36:25 【问题描述】:将 ASP.NET Core (.NET 5) Blazor 服务器与 OKTA 结合使用。 OKTA 日志页面已提示。我在提交 OKTA uid/pwd 时收到错误消息
HTTP Error 400. The size of the request headers is too long.
我的中间件如下所示,使用 OpenId Connect。
services.AddAuthentication(options =>
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
)
.AddOpenIdConnect(options =>
options.RemoteAuthenticationTimeout = TimeSpan.FromMinutes(30);
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = configuration["Okta:Domain"] + "/oauth2/default";
options.RequireHttpsMetadata = true;
options.ClientId = configuration["Okta:ClientId"];
options.ClientSecret = configuration["Okta:ClientSecret"];
options.ResponseMode = OpenIdConnectResponseMode.FormPost;
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Add("offline_access");
options.UseTokenLifetime = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.AccessDeniedPath = "/Public/AccessDenied";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
// Describe how to map the user info we receive to user claims
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub", "string");
options.ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name", "string");
options.ClaimActions.MapJsonKey(ClaimTypes.Name, "given_name", "string");
options.ClaimActions.MapJsonKey("LastName", "lastname", "string");
options.ClaimActions.MapJsonKey("FirstName", "firstname", "string");
options.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", "string");
options.ClaimActions.MapJsonKey("Groups", "Groups", "string");
options.ClaimActions.MapJsonKey("membership_roles", "membership_roles", "string");
options.SaveTokens = true;
options.NonceCookie.SameSite = SameSiteMode.Unspecified;
options.CorrelationCookie.SameSite = SameSiteMode.Unspecified;
options.TokenValidationParameters = new TokenValidationParameters
NameClaimType = "name",
RoleClaimType = "groups",
RequireSignedTokens = true,
ValidateIssuer = false
;
)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, displayName: $"EPDOne_GlobalVariables.LocalEnv.EnvironmentName",
options =>
options.Cookie.Name = $"EPDOne_ GlobalVariables.LocalEnv.EnvironmentName";
options.Cookie.HttpOnly = false;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Cookie.IsEssential = true;
options.Events = new CookieAuthenticationEvents
// this event is fired everytime the cookie has been validated by the cookie middleware,
// so basically during every authenticated request
// the decryption of the cookie has already happened so we have access to the user claims
// and cookie properties - expiration, etc..
OnValidatePrincipal = context =>
// since our cookie lifetime is based on the access token one,
// check if we're more than halfway of the cookie lifetime
var now = DateTimeOffset.UtcNow;
TimeSpan timeElapsed = now.Subtract(DateTime.Now.AddDays(1));
TimeSpan timeRemaining = now.Subtract(DateTime.Now.AddDays(2));
if (context is not null)
if (context.Properties is not null && context.Properties.IssuedUtc is not null)
timeElapsed = now.Subtract(context.Properties.IssuedUtc.Value);
else
context.ShouldRenew = true;
if (context.Properties is not null && context.Properties.ExpiresUtc is not null)
timeRemaining = context.Properties.ExpiresUtc.Value.Subtract(now);
else
context.ShouldRenew = true;
if (timeElapsed > timeRemaining || context?.ShouldRenew == true)
context.ShouldRenew = true;
var identity = (ClaimsIdentity)context?.Principal?.Identity;
if (identity is not null && identity.IsAuthenticated)
string CurrentBaseAddress = CurrentURL(context.HttpContext);
string returnUrl = "";
if (string.IsNullOrEmpty(CurrentBaseAddress) == false)
returnUrl = "?returnUrl=" + CurrentBaseAddress;
context.Response.Redirect(GlobalVariables.OKTACallBackURI + $"/refreshreturnUrl");
return Task.CompletedTask;
;
);
services.AddRazorPages(options =>
options.Conventions.AuthorizeFolder("/");
//options.Conventions.AllowAnonymousToFolder("/Public");
);
正如您在上面看到的,我在 Startup.cs 中使用了 OpenId,应用程序通过 OKTA 凭据对话框进行提示,在提交 uid/pwd 后,页面的行为就像在循环中,然后显示 HTTP 错误 400 消息。这里有什么线索吗?
【问题讨论】:
您是否有从浏览器收集的网络流量(HAR 文件),以查看导致 400 的原因或发生循环的位置? 是的。我在这里应付了1drv.ms/u/s!ArnWsPocPHeKhZgv_lNQbeSTpJfviA?e=OAWU50。我在另一个简单的应用程序中本地使用了相同的本地主机配置,它可以工作。 从我在 HAR 中看到的情况来看,当调用/authorize
时,要求重定向为 /signin-oidc
。因此,当您使用代码重定向到那里时,/signin-oidc
不会正确处理它(似乎)并将您发送回/authorize
。在这一点上,我可能没用了,因为必须有人可以根据您收集的信息为您建议 .net 应用程序配置更改
【参考方案1】:
Philipp Grigoryev - 感谢您的宝贵时间。我后来在我的 .NET Core Startup.cs 文件中发现了下面的代码。
app.UseAuthorization();
app.UseAuthorization();
正确的行应该是
app.UseAuthentication();
app.UseAuthorization();
所以实际上身份验证中间件本身没有启用,我匆忙使用了两行启用授权本身。在提到的更正之后,它可以工作。对不起任何花时间在这上面的人。我正在关闭此查询。
【讨论】:
以上是关于.NET 5 Blazor 服务器 OKTA 身份验证显示 HTTP 错误 400的主要内容,如果未能解决你的问题,请参考以下文章
Microsoft Graph API - Blazor Server App .NET 5.0 使用 Azure 身份验证,MsalUiRequiredException 因用户质询而引发
从 ASP.NET/Blazor 服务器中的当前经过身份验证的用户获取数据