【发布时间】: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 + $"/refresh{returnUrl}");
}
}
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 应用程序配置更改
标签: asp.net-core blazor-server-side okta