aspnetcore/blazor/security/gdpr.md
This article explains how to implement support for EU General Data Protection Regulation (GDPR) requirements.
:::zone pivot="server"
In the Program file:
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
builder.Services.AddHttpContextAccessor();
:::moniker range=">= aspnetcore-8.0"
In the Program file before the call to xref:Microsoft.AspNetCore.Builder.RazorComponentsEndpointRouteBuilderExtensions.MapRazorComponents%2A, add Cookie Policy Middleware by calling xref:Microsoft.AspNetCore.Builder.CookiePolicyAppBuilderExtensions.UseCookiePolicy%2A:
:::moniker-end
:::moniker range="< aspnetcore-8.0"
In the Program file before the call to xref:Microsoft.AspNetCore.Builder.ComponentEndpointRouteBuilderExtensions.MapBlazorHub%2A, add Cookie Policy Middleware by calling xref:Microsoft.AspNetCore.Builder.CookiePolicyAppBuilderExtensions.UseCookiePolicy%2A:
:::moniker-end
app.UseCookiePolicy();
Add the following CookieConsent component to handle cookie policy consent.
The component uses a collocated JavaScript file, named CookieConsent.razor.js, to load a module. Confirm or adjust the path to the collocated file in the OnAfterRenderAsync method. The following component assumes that the component and its companion JavaScript file are in the Components folder of the app.
CookieConsent.razor:
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Http
@implements IAsyncDisposable
@inject IHttpContextAccessor Http
@inject IJSRuntime JS
@if (showBanner)
{
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show"
role="alert">
Use this space to summarize your privacy and cookie use policy.
<a href="/privacy">Privacy Policy</a>
<button type="button" @onclick="AcceptPolicy" class="accept-policy close"
data-bs-dismiss="alert" aria-label="Close"
data-cookie-string="@cookieString">
Accept
</button>
</div>
}
@code {
private IJSObjectReference? module;
private ITrackingConsentFeature? consentFeature;
private bool showBanner;
private string? cookieString;
protected override void OnInitialized()
{
consentFeature = Http.HttpContext?.Features.Get<ITrackingConsentFeature>();
showBanner = !consentFeature?.CanTrack ?? false;
cookieString = consentFeature?.CreateConsentCookie();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Components/CookieConsent.razor.js");
}
}
private async Task AcceptPolicy()
{
if (module is not null)
{
await module.InvokeVoidAsync("acceptPolicy", cookieString);
showBanner = false;
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
Add the following collocated JavaScript file to maintain the acceptPolicy function in a JavaScript module.
CookieConsent.razor.js:
export function acceptPolicy(cookieString) {
document.cookie = cookieString;
}
Within <main> Razor markup of the MainLayout component (MainLayout.razor), add the CookieConsent component:
<CookieConsent />
Specify the cookie consent value by assigning a custom string to xref:Microsoft.AspNetCore.Builder.CookiePolicyOptions.ConsentCookieValue%2A?displayProperty=nameWithType. The following example changes the default value of "yes" to "true":
options.ConsentCookieValue = "true";
:::zone-end
:::zone pivot="webassembly"
In Blazor WebAssembly apps, local storage is a convenient approach for maintaining a user's acceptance of a site's cookie policy. The following approach demonstrates the approach.
If the app doesn't already have a Shared folder for shared components, add a Shared folder to the app.
Add the namespace for shared components to the _Imports.razor file. In the following example, the app's namespace is BlazorSample, and the shared folder's namespace is BlazorSample.Shared:
@using BlazorSample.Shared
Add the following CookieConsent component to handle cookie policy consent.
Shared/CookieConsent.razor:
@implements IAsyncDisposable
@inject IJSRuntime JS
@if (showBanner)
{
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show"
role="alert">
Use this space to summarize your privacy and cookie use policy.
<a href="/privacy">Privacy Policy</a>
<button type="button" @onclick="AcceptPolicy" class="accept-policy close"
data-bs-dismiss="alert" aria-label="Close">
<span aria-hidden="true">Accept</span>
</button>
</div>
}
@code {
private IJSObjectReference? module;
private bool showBanner = false;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import",
"./Shared/CookieConsent.razor.js");
showBanner = !await module.InvokeAsync<bool>("getCookiePolicyAccepted");
StateHasChanged();
}
}
private async Task AcceptPolicy()
{
if (module is not null)
{
await module.InvokeVoidAsync("setCookiePolicyAccepted");
showBanner = false;
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
try
{
await module.DisposeAsync();
}
catch (JSDisconnectedException)
{
}
}
}
}
Add the following collocated JavaScript file to maintain the setCookiePolicyAccepted and getCookiePolicyAccepted functions in a JavaScript module.
Shared/CookieConsent.razor.js:
export function getCookiePolicyAccepted() {
const cookiePolicy = localStorage.getItem('CookiePolicyAccepted');
return cookiePolicy === 'yes' ? true : false;
}
export function setCookiePolicyAccepted() {
localStorage.setItem('CookiePolicyAccepted', 'yes');
}
In the preceding example, you can change the name of the local storage item and value from "CookiePolicyAccepted" and "yes" to any preferred values. If you change one or both values, update both functions.
Within <main> Razor markup of the MainLayout component (Layout/MainLayout.razor), add the CookieConsent component:
<CookieConsent />
:::zone-end