c# - CodeVerification Cookie 在 Edge 和 Chrome 中消失
问题描述
.NET 框架 4.6.1 网站使用 OIDC 身份验证 (Microsoft.Owin.Security.OpenIdConnect 4.1.0) 作为身份验证的一部分,我包括“code_challenge”。以下代码基于此示例。
RedirectToIdentityProvider = n =>
{
//ProcessCertificateValidation();
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
{
if (AppSettingsKey.AuthCodeChallangeEnabled.Enabled)
{
// generate code verifier and code challenge
var codeVerifier = CryptoRandom.CreateUniqueId(32);
string codeChallenge;
using (var sha256 = SHA256.Create())
{
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
codeChallenge = Base64UrlEncoder.Encode(challengeBytes);
}
// set code_challenge parameter on authorization request
n.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge);
n.ProtocolMessage.Parameters.Add("code_challenge_method", "S256");
// remember code verifier in cookie (adapted from OWIN nonce cookie)
RememberCodeVerifier(n, codeVerifier);
}
if (AppSettingsKey.MultiFactorAuthEnabled.Enabled)
n.ProtocolMessage.AcrValues = authCfg.AcrValues ?? n.ProtocolMessage.AcrValues;
}
logger.Debug("OIDC-Notification: RedirectToIdentityProvider Called");
//if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
logger.Debug(" RequestType=" + OpenIdConnectRequestType.Logout);
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
logger.Debug(" IdTokenHint got from n.OwinContext.Authentication.User");
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
logger.Debug(" IdTokenHint=" + n?.ProtocolMessage?.IdTokenHint);
}
return Task.CompletedTask;
},
我确认发送了“codeVerifierCookie”。
AuthorizationCodeReceived = async n =>
{
logger.Debug("OIDC-Notification: AuthorizationCodeReceived Called");
logger.Debug(" Code=" + n.Code);
logger.Debug(" AuthenticationType=" + n.Options.AuthenticationType);
if (authCfg.DiscoverEndpoints)
{
var disco = await n.Options.ConfigurationManager.GetConfigurationAsync(n.OwinContext.Request.CallCancelled);
authCfg.TokenEndpoint = disco.TokenEndpoint;
authCfg.UserinfoEndpoint = disco.UserInfoEndpoint;
authCfg.EndsessionEndpoint = disco.EndSessionEndpoint;
//authCfg.RevocationEndpoint = disco.RevocationEndpoint;
authCfg.WebKeySetEndpoint = disco.JwksUri;
}
if (AppSettingsKey.AuthCodeChallangeEnabled.Enabled) {
var codeVerifier = RetrieveCodeVerifier(n);
// attach code_verifier
n.TokenEndpointRequest.SetParameter("code_verifier", codeVerifier);
}
var requestMessage = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, authCfg.TokenEndpoint);
requestMessage.Content = new System.Net.Http.FormUrlEncodedContent(n.TokenEndpointRequest.Parameters);
var responseMessage = await n.Options.Backchannel.SendAsync(requestMessage);
responseMessage.EnsureSuccessStatusCode();
var responseContent = await responseMessage.Content.ReadAsStringAsync();
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage message = new Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage(responseContent);
logger.Debug(" IdToken=" + message.IdToken);
logger.Debug(" AccessToken=" + message.AccessToken);
n.HandleCodeRedemption(message);
},
问题是,当尝试检索“codeVerifierCookie”时,它不存在,当尝试登录 Edge 或 Chrome(在 Firefox 上)时。
以下是用于发送、检索和获取验证码的方法。CookieManager 配置为Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager()
.
private void RememberCodeVerifier(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> n, string codeVerifier)
{
var properties = new AuthenticationProperties();
properties.Dictionary.Add("cv", codeVerifier);
n.Options.CookieManager.AppendResponseCookie(
n.OwinContext,
GetCodeVerifierKey(n.ProtocolMessage.State),
Convert.ToBase64String(Encoding.UTF8.GetBytes(n.Options.StateDataFormat.Protect(properties))),
new CookieOptions
{
SameSite = SameSiteMode.None,
HttpOnly = true,
Secure = n.Request.IsSecure,
Expires = DateTime.UtcNow + n.Options.ProtocolValidator.NonceLifetime
});
}
private string RetrieveCodeVerifier(AuthorizationCodeReceivedNotification n)
{
string key = GetCodeVerifierKey(n.ProtocolMessage.State);
string codeVerifierCookie = n.Options.CookieManager.GetRequestCookie(n.OwinContext, key);
if (codeVerifierCookie != null)
{
var cookieOptions = new CookieOptions
{
SameSite = SameSiteMode.None,
HttpOnly = true,
Secure = n.Request.IsSecure
};
n.Options.CookieManager.DeleteCookie(n.OwinContext, key, cookieOptions);
}
var cookieProperties = n.Options.StateDataFormat.Unprotect(Encoding.UTF8.GetString(Convert.FromBase64String(codeVerifierCookie)));
cookieProperties.Dictionary.TryGetValue("cv", out var codeVerifier);
return codeVerifier;
}
private string GetCodeVerifierKey(string state)
{
using (var hash = SHA256.Create())
{
return OpenIdConnectAuthenticationDefaults.CookiePrefix + "cv." + Convert.ToBase64String(hash.ComputeHash(Encoding.UTF8.GetBytes(state)));
}
}
为什么我尝试从 Edge 或 Chrome 登录时缺少“codeVerifierCookie”?可能是一些默认设置还是我的设置缺少某些东西?为什么它可以在 Firefox 上运行?
感谢您阅读我的帖子,我欢迎有关此问题的所有意见。
解决方案
你在测试你的应用程序时使用过 HTTPS 吗?断言的 CookieSameSite=None
也必须标记为Secure
. 我认为这个问题可能与同一站点 cookie 设置有关。
我找到了一个和你有同样问题的帖子,你可以参考一下。此外,还有一篇关于在 ASP.NET 中使用 SameSite cookie 的详细文章,您也可以查看它以获取更多信息。
推荐阅读
- c - 尽管有 STM32 构建错误“无法打开链接器脚本文件”
- typescript - 打字稿:得到右手边算术错误
- wordpress - 如何将子域重定向到路径 AWS EC2 apache 服务器和 cloudflare
- python - 如何使用 Blogger API 插入图片
- grails - 阻止字段插件舍入我的浮点数
- php - PHP 7.4 没有“看到”自定义编译的扩展
- kotlin - 如何以编程方式在 NestedScrollView 内将普通 EditText 制作为 Multiline EditText 并使 MultiLineEdittext 在 Nedted Scroll View 内滚动?
- intellij-idea - 在 .editorconfig 文件中保留 IntelliJ IDEA“Kotlin | 样式问题”设置
- api - 如何在不共享密钥的情况下共享使用私有 API 密钥的程序?
- css - 为什么我的按钮悬停功能不起作用?