CodeVerification Cookie 在 Edge 中消失 Chrome
CodeVerification Cookie disappears in Edge and Chrome
.NET framework 4.6.1网站使用OIDC认证(Microsoft.Owin.Security.OpenIdConnect4.1.0)
作为身份验证的一部分,我包括“code_challenge”。下面的代码是基于这个example.
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 上运行?
感谢您阅读我的 post,我欢迎您就此问题发表任何意见。
您在测试您的应用时是否使用了 HTTPS?声明 SameSite=None
的 Cookie 也必须标记为 Secure
。我认为这个问题可能与 Same-Site cookies 设置有关。
我在 ASP.NET 中找到 which has the same issue as yours, you can refer to it. Besides, there's a detailed article 关于使用 SameSite cookie 的信息,您也可以查看它以获取更多信息。
.NET framework 4.6.1网站使用OIDC认证(Microsoft.Owin.Security.OpenIdConnect4.1.0) 作为身份验证的一部分,我包括“code_challenge”。下面的代码是基于这个example.
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 上运行?
感谢您阅读我的 post,我欢迎您就此问题发表任何意见。
您在测试您的应用时是否使用了 HTTPS?声明 SameSite=None
的 Cookie 也必须标记为 Secure
。我认为这个问题可能与 Same-Site cookies 设置有关。
我在 ASP.NET 中找到