Background and Motivation
Currently, the cookie consent validation performs an equality comparison against the constant cookie value yes. It will add more flexibility if the value can be customized, especially when supporting an already existing cookie consent.
I already made the changes in my fork and added some tests, you can see them right here 68180e5.
Proposed API
namespace Microsoft.AspNetCore.Builder;
public class CookiePolicyOptions
{
/// <summary>
/// Gets or sets the <see cref="CookieBuilder"/> that is used to track if the user consented to the
/// cookie use policy.
/// </summary>
public CookieBuilder ConsentCookie { get; set; } = new CookieBuilder()
{
Name = ".AspNet.Consent",
Expiration = TimeSpan.FromDays(365),
IsEssential = true,
};
+ /// <summary>
+ /// Gets or sets the consent value that is used to track if the user consented to the
+ /// cookie use policy. The default is yes.
+ /// </summary>
+ public string ConsentCookieValue { get; set; } = "yes";
}
namespace Microsoft.AspNetCore.CookiePolicy;
internal class ResponseCookiesWrapper : IResponseCookies, ITrackingConsentFeature
{
- private const string ConsentValue = "yes";
+ private const string DefaultConsentValue = "yes";
private readonly ILogger _logger;
private bool? _isConsentNeeded;
private bool? _hasConsent;
public ResponseCookiesWrapper(HttpContext context, CookiePolicyOptions options, IResponseCookiesFeature feature, ILogger logger)
{
Context = context;
Feature = feature;
Options = options;
_logger = logger;
+ if (string.IsNullOrWhiteSpace(Options.ConsentCookieValue))
+ {
+ Options.ConsentCookieValue = DefaultConsentValue;
+ }
}
public bool HasConsent
{
get
{
if (!_hasConsent.HasValue)
{
var cookie = Context.Request.Cookies[Options.ConsentCookie.Name!];
- _hasConsent = string.Equals(cookie, ConsentValue, StringComparison.Ordinal);
+ _hasConsent = string.Equals(cookie, Options.ConsentCookieValue, StringComparison.Ordinal);
_logger.HasConsent(_hasConsent.Value);
}
return _hasConsent.Value;
}
}
public void GrantConsent()
{
if (!HasConsent && !Context.Response.HasStarted)
{
var cookieOptions = Options.ConsentCookie.Build(Context);
// Note policy will be applied. We don't want to bypass policy because we want HttpOnly, Secure, etc. to apply.
- Append(Options.ConsentCookie.Name!, ConsentValue, cookieOptions);
+ Append(Options.ConsentCookie.Name!, Options.ConsentCookieValue, cookieOptions);
_logger.ConsentGranted();
}
_hasConsent = true;
}
public string CreateConsentCookie()
{
var key = Options.ConsentCookie.Name;
- var value = ConsentValue;
+ var value = Options.ConsentCookieValue;
var options = Options.ConsentCookie.Build(Context);
Debug.Assert(key != null);
ApplyAppendPolicy(ref key, ref value, options);
var setCookieHeaderValue = new Net.Http.Headers.SetCookieHeaderValue(
Uri.EscapeDataString(key),
Uri.EscapeDataString(value))
{
Domain = options.Domain,
Path = options.Path,
Expires = options.Expires,
MaxAge = options.MaxAge,
Secure = options.Secure,
SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite,
HttpOnly = options.HttpOnly
};
return setCookieHeaderValue.ToString();
}
}
Usage Examples
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.ConsentCookieValue = "true";
});
Alternative Designs
None at the moment.
Risks
I don't see any breaking changes since the default value for the cookie consent will remain as yes.
Background and Motivation
Currently, the cookie consent validation performs an equality comparison against the constant cookie value
yes. It will add more flexibility if the value can be customized, especially when supporting an already existing cookie consent.I already made the changes in my fork and added some tests, you can see them right here 68180e5.
Proposed API
namespace Microsoft.AspNetCore.Builder; public class CookiePolicyOptions { /// <summary> /// Gets or sets the <see cref="CookieBuilder"/> that is used to track if the user consented to the /// cookie use policy. /// </summary> public CookieBuilder ConsentCookie { get; set; } = new CookieBuilder() { Name = ".AspNet.Consent", Expiration = TimeSpan.FromDays(365), IsEssential = true, }; + /// <summary> + /// Gets or sets the consent value that is used to track if the user consented to the + /// cookie use policy. The default is yes. + /// </summary> + public string ConsentCookieValue { get; set; } = "yes"; }namespace Microsoft.AspNetCore.CookiePolicy; internal class ResponseCookiesWrapper : IResponseCookies, ITrackingConsentFeature { - private const string ConsentValue = "yes"; + private const string DefaultConsentValue = "yes"; private readonly ILogger _logger; private bool? _isConsentNeeded; private bool? _hasConsent; public ResponseCookiesWrapper(HttpContext context, CookiePolicyOptions options, IResponseCookiesFeature feature, ILogger logger) { Context = context; Feature = feature; Options = options; _logger = logger; + if (string.IsNullOrWhiteSpace(Options.ConsentCookieValue)) + { + Options.ConsentCookieValue = DefaultConsentValue; + } } public bool HasConsent { get { if (!_hasConsent.HasValue) { var cookie = Context.Request.Cookies[Options.ConsentCookie.Name!]; - _hasConsent = string.Equals(cookie, ConsentValue, StringComparison.Ordinal); + _hasConsent = string.Equals(cookie, Options.ConsentCookieValue, StringComparison.Ordinal); _logger.HasConsent(_hasConsent.Value); } return _hasConsent.Value; } } public void GrantConsent() { if (!HasConsent && !Context.Response.HasStarted) { var cookieOptions = Options.ConsentCookie.Build(Context); // Note policy will be applied. We don't want to bypass policy because we want HttpOnly, Secure, etc. to apply. - Append(Options.ConsentCookie.Name!, ConsentValue, cookieOptions); + Append(Options.ConsentCookie.Name!, Options.ConsentCookieValue, cookieOptions); _logger.ConsentGranted(); } _hasConsent = true; } public string CreateConsentCookie() { var key = Options.ConsentCookie.Name; - var value = ConsentValue; + var value = Options.ConsentCookieValue; var options = Options.ConsentCookie.Build(Context); Debug.Assert(key != null); ApplyAppendPolicy(ref key, ref value, options); var setCookieHeaderValue = new Net.Http.Headers.SetCookieHeaderValue( Uri.EscapeDataString(key), Uri.EscapeDataString(value)) { Domain = options.Domain, Path = options.Path, Expires = options.Expires, MaxAge = options.MaxAge, Secure = options.Secure, SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite, HttpOnly = options.HttpOnly }; return setCookieHeaderValue.ToString(); } }Usage Examples
Alternative Designs
None at the moment.
Risks
I don't see any breaking changes since the default value for the cookie consent will remain as
yes.