Skip to content

Instantly share code, notes, and snippets.

@Maarten88
Last active March 27, 2023 21:33
Show Gist options
  • Save Maarten88/5778402 to your computer and use it in GitHub Desktop.
Save Maarten88/5778402 to your computer and use it in GitHub Desktop.
ASP.NET ActionFilterAttribute to help implement european cookie-law
/*
* ASP.NET ActionFilterAttribute to help implement EU Cookie-law
* MIT Licence (c) Maarten Sikkema, Macaw Nederland BV
*/
using System;
using System.Web;
using System.Web.Mvc;
namespace Auction.Web.Utility
{
/// <summary>
/// ASP.NET MVC FilterAttribute for implementing european cookie-law
/// </summary>
public class CookieConsentAttribute : ActionFilterAttribute
{
public const string CONSENT_COOKIE_NAME = "CookieConsent";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var viewBag = filterContext.Controller.ViewBag;
viewBag.AskCookieConsent = true;
viewBag.HasCookieConsent = false;
var request = filterContext.HttpContext.Request;
// Check if the user has a consent cookie
var consentCookie = request.Cookies[CONSENT_COOKIE_NAME];
if (consentCookie == null)
{
// No consent cookie. We first check the Do Not Track header value, this can have the value "0" or "1"
string dnt = request.Headers.Get("DNT");
// If we receive a DNT header, we accept its value and do not ask the user anymore
if (!String.IsNullOrEmpty(dnt))
{
viewBag.AskCookieConsent = false;
if (dnt == "0")
{
viewBag.HasCookieConsent = true;
}
}
else
{
if (IsSearchCrawler(request.Headers.Get("User-Agent")))
{
// don't ask consent from search engines, also don't set cookies
viewBag.AskCookieConsent = false;
}
else
{
// first request on the site and no DNT header.
consentCookie = new HttpCookie(CONSENT_COOKIE_NAME);
consentCookie.Value = "asked";
filterContext.HttpContext.Response.Cookies.Add(consentCookie);
}
}
}
else
{
// we received a consent cookie
viewBag.AskCookieConsent = false;
if (consentCookie.Value == "asked")
{
// consent is implicitly given
consentCookie.Value = "true";
consentCookie.Expires = DateTime.UtcNow.AddYears(1);
filterContext.HttpContext.Response.Cookies.Set(consentCookie);
viewBag.HasCookieConsent = true;
}
else if (consentCookie.Value == "true")
{
viewBag.HasCookieConsent = true;
}
else
{
// assume consent denied
viewBag.HasCookieConsent = false;
}
}
base.OnActionExecuting(filterContext);
}
private bool IsSearchCrawler(string userAgent)
{
if (!userAgent.IsNullOrEmpty())
{
string[] crawlers = new string[]
{
"Baiduspider",
"Googlebot",
"YandexBot",
"YandexImages",
"bingbot",
"msnbot",
"Vagabondo",
"SeznamBot",
"ia_archiver",
"AcoonBot",
"Yahoo! Slurp",
"AhrefsBot"
};
foreach (string crawler in crawlers)
if (userAgent.Contains(crawler))
return true;
}
return false;
}
}
/// <summary>
/// Helper class for easy/typesafe getting the cookie consent status
/// </summary>
public static class CookieConsent
{
public static void SetCookieConsent(HttpResponseBase response, bool consent)
{
var consentCookie = new HttpCookie(CookieConsentAttribute.CONSENT_COOKIE_NAME);
consentCookie.Value = consent ? "true" : "false";
consentCookie.Expires = DateTime.UtcNow.AddYears(1);
response.Cookies.Set(consentCookie);
}
public static bool AskCookieConsent(ViewContext context)
{
return context.ViewBag.AskCookieConsent ?? false;
}
public static bool HasCookieConsent(ViewContext context)
{
return context.ViewBag.HasCookieConsent ?? false;
}
}
}
@hidegh
Copy link

hidegh commented Feb 18, 2015

Little changes:

  • allow to disable implicit consent after 1st popup
  • using HttpContext.Current.Item and private class instead of ViewBag
  • simpler methods (do not need Response) - and changed to property

Still, THANX for it!

    public class CookieConsentFilter : ActionFilterAttribute
    {
        /// <summary>
        /// Some government relax their interpretation of the law somewhat:
        /// After the first page with the message, clicking anything other than the cookie refusal link may be interpreted as implicitly allowing cookies. 
        /// </summary>
        public bool ImplicitlyAllowCookies { get; set; }

        public CookieConsentFilter()
        {
            ImplicitlyAllowCookies = true;
        }

        private const string cookieConsentCookieName = "cookieConsent";
        private const string cookieConsentContextName = "cookieConsentInfo";

        private class CookieConsentInfo
        {
            public bool NeedToAskConsent { get; set; }
            public bool HasConsent { get; set; }

            public CookieConsentInfo()
            {
                NeedToAskConsent = true;
                HasConsent = false;
            }
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var consentInfo = new CookieConsentInfo();

            var request = filterContext.HttpContext.Request;

            // Check if the user has a consent cookie
            var consentCookie = request.Cookies[cookieConsentCookieName];

            if (consentCookie == null)
            {
                // No consent cookie. We first check the Do Not Track header value, this can have the value "0" or "1"
                string dnt = request.Headers.Get("DNT");

                // If we receive a DNT header, we accept its value (0 = give consent, 1 = deny) and do not ask the user anymore...
                if (!String.IsNullOrEmpty(dnt))
                {
                    consentInfo.NeedToAskConsent = false;

                    if (dnt == "0")
                    {
                        consentInfo.HasConsent = true;
                    }
                }
                else
                {
                    if (IsSearchCrawler(request.Headers.Get("User-Agent")))
                    {
                        // don't ask consent from search engines, also don't set cookies
                        consentInfo.NeedToAskConsent = false;
                    }
                    else
                    {
                        // first request on the site and no DNT header (we use session cookie, which is allowed by EU cookie law). 
                        consentCookie = new HttpCookie(cookieConsentCookieName);
                        consentCookie.Value = "asked";

                        filterContext.HttpContext.Response.Cookies.Add(consentCookie);
                    }
                }
            }
            else
            {
                // we received a consent cookie
                consentInfo.NeedToAskConsent = false;

                if (ImplicitlyAllowCookies && consentCookie.Value == "asked")
                {
                    // consent is implicitly given & stored
                    consentCookie.Value = "true";
                    consentCookie.Expires = DateTime.UtcNow.AddYears(1);
                    filterContext.HttpContext.Response.Cookies.Set(consentCookie);

                    consentInfo.HasConsent = true;
                }
                else if (consentCookie.Value == "true")
                {
                    consentInfo.HasConsent = true;
                }
                else
                {
                    // assume consent denied
                    consentInfo.HasConsent = false;
                }
            }

            HttpContext.Current.Items[cookieConsentContextName] = consentInfo;

            base.OnActionExecuting(filterContext);
        }

        private bool IsSearchCrawler(string userAgent)
        {
            if (!string.IsNullOrEmpty(userAgent))
            {
                string[] crawlers = new string[]
                {
                    "Baiduspider",
                    "Googlebot",
                    "YandexBot",
                    "YandexImages",
                    "bingbot",
                    "msnbot",
                    "Vagabondo",
                    "SeznamBot",
                    "ia_archiver",
                    "AcoonBot",
                    "Yahoo! Slurp",
                    "AhrefsBot"
                };
                foreach (string crawler in crawlers)
                    if (userAgent.Contains(crawler))
                        return true;
            }
            return false;
        }

        public static void SetCookieConsent(bool consent)
        {
            var consentCookie = new HttpCookie(CookieConsentFilter.cookieConsentCookieName);
            consentCookie.Value = consent ? "true" : "false";
            consentCookie.Expires = DateTime.UtcNow.AddYears(1);
            HttpContext.Current.Response.Cookies.Set(consentCookie);
        }

        public static bool NeedToAskCookieConsent
        {
            get { return (HttpContext.Current.Items[cookieConsentContextName] as CookieConsentInfo ?? new CookieConsentInfo()).NeedToAskConsent; }
        }

        public static bool HasConsent
        {
            get { return (HttpContext.Current.Items[cookieConsentContextName] as CookieConsentInfo ?? new CookieConsentInfo()).HasConsent; }
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment