diff --git a/aspnetcore/blazor/security/gdpr.md b/aspnetcore/blazor/security/gdpr.md new file mode 100644 index 000000000000..bb8554b3cde2 --- /dev/null +++ b/aspnetcore/blazor/security/gdpr.md @@ -0,0 +1,251 @@ +--- +title: EU General Data Protection Regulation (GDPR) support in ASP.NET Core Blazor +author: guardrex +description: Learn how to implement EU General Data Protection Regulation (GDPR) support in Blazor apps. +monikerRange: '>= aspnetcore-6.0' +ms.author: riande +ms.custom: mvc +ms.date: 01/16/2025 +uid: blazor/security/gdpr +zone_pivot_groups: blazor-app-models +--- +# EU General Data Protection Regulation (GDPR) support in ASP.NET Core Blazor + +[!INCLUDE[](~/includes/not-latest-version.md)] + +This article explains how to implement support for [EU General Data Protection Regulation (GDPR)](https://ec.europa.eu/info/law/law-topic/data-protection/reform/what-does-general-data-protection-regulation-gdpr-govern_en) requirements. + +:::zone pivot="server" + +In the `Program` file: + +* Add configuration to require user consent for non-essential cookies and set the same-site policy to none. For more information, see . +* Add the default implementation for the service by calling . + +```csharp +builder.Services.Configure(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 , add Cookie Policy Middleware by calling : + +:::moniker-end + +:::moniker range="< aspnetcore-8.0" + +In the `Program` file before the call to , add Cookie Policy Middleware by calling : + +:::moniker-end + +```csharp +app.UseCookiePolicy(); +``` + +Add the following `CookieConsent` component to handle cookie policy consent. + +The component uses a [collocated JavaScript file](xref:blazor/js-interop/javascript-location#load-a-script-from-an-external-javascript-file-js-collocated-with-a-component), 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`: + +```razor +@using Microsoft.AspNetCore.Http.Features +@using Microsoft.AspNetCore.Http +@implements IAsyncDisposable +@inject IHttpContextAccessor Http +@inject IJSRuntime JS + +@if (showBanner) +{ + +} +@code { + private IJSObjectReference? module; + private ITrackingConsentFeature? consentFeature; + private bool showBanner; + private string? cookieString; + + protected override void OnInitialized() + { + consentFeature = Http.HttpContext?.Features.Get(); + showBanner = !consentFeature?.CanTrack ?? false; + cookieString = consentFeature?.CreateConsentCookie(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + module = await JS.InvokeAsync("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](xref:blazor/js-interop/javascript-location#load-a-script-from-an-external-javascript-file-js-collocated-with-a-component) to maintain the `acceptPolicy` function in a JavaScript module. + +`CookieConsent.razor.js`: + +```javascript +export function acceptPolicy(cookieString) { + document.cookie = cookieString; +} +``` + +Within `
` Razor markup of the `MainLayout` component (`MainLayout.razor`), add the `CookieConsent` component: + +```razor + +``` + +## Customize the cookie consent value + +Specify the cookie consent value by assigning a custom string to . The following example changes the default value of "`yes`" to "`true`": + +```csharp +options.ConsentCookieValue = "true"; +``` + +:::zone-end + +:::zone pivot="webassembly" + +In Blazor WebAssembly apps, [local storage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) 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`: + +```razor +@using BlazorSample.Shared +``` + +Add the following `CookieConsent` component to handle cookie policy consent. + +`Shared/CookieConsent.razor`: + +```razor +@implements IAsyncDisposable +@inject IJSRuntime JS + +@if (showBanner) +{ + +} +@code { + private IJSObjectReference? module; + private bool showBanner = false; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + module = await JS.InvokeAsync("import", + "./Shared/CookieConsent.razor.js"); + showBanner = !await module.InvokeAsync("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](xref:blazor/js-interop/javascript-location#load-a-script-from-an-external-javascript-file-js-collocated-with-a-component) to maintain the `setCookiePolicyAccepted` and `getCookiePolicyAccepted` functions in a JavaScript module. + +`Shared/CookieConsent.razor.js`: + +```javascript +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 `
` Razor markup of the `MainLayout` component (`Layout/MainLayout.razor`), add the `CookieConsent` component: + +```razor + +``` + +:::zone-end + +## Additional resources + +* [Microsoft Trust Center: Safeguard individual privacy with cloud services from Microsoft: GDPR](https://www.microsoft.com/trust-center/privacy/gdpr-overview) +* [European Commission: Data protection explained](https://ec.europa.eu/info/law/law-topic/data-protection/reform/what-does-general-data-protection-regulation-gdpr-govern_en) diff --git a/aspnetcore/security/gdpr.md b/aspnetcore/security/gdpr.md index 7ea6b377e798..eaa0316fa9d4 100644 --- a/aspnetcore/security/gdpr.md +++ b/aspnetcore/security/gdpr.md @@ -18,6 +18,8 @@ ASP.NET Core provides APIs and templates to help meet some of the [EU General Da * The project templates include extension points and stubbed markup that you can replace with your privacy and cookie use policy. * The `Pages/Privacy.cshtml` page or `Views/Home/Privacy.cshtml` view provides a page to detail your site's privacy policy. +For GDPR guidance that applies to Blazor apps, see . + To enable the default cookie consent feature like that found in the ASP.NET Core 2.2 templates in a current ASP.NET Core template generated app, add the following highlighted code to `Program.cs`: [!code-csharp[Main](~/security/gdpr/sample/RP6.0/WebGDPR/Program.cs?name=snippet_1&highlight=4-11,23)] @@ -64,7 +66,8 @@ For databases that don't provide built-in encryption at rest, you may be able to ## Additional resources -* [Microsoft.com/GDPR](https://www.microsoft.com/trustcenter/Privacy/GDPR) +* [Microsoft Trust Center: Safeguard individual privacy with cloud services from Microsoft: GDPR](https://www.microsoft.com/trust-center/privacy/gdpr-overview) +* [European Commission: Data protection explained](https://ec.europa.eu/info/law/law-topic/data-protection/reform/what-does-general-data-protection-regulation-gdpr-govern_en) :::moniker-end diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 7325831f1ee7..f9baa66412f1 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -624,6 +624,8 @@ items: uid: blazor/security/qrcodes-for-authenticator-apps - name: Content Security Policy uid: blazor/security/content-security-policy + - name: EU General Data Protection Regulation (GDPR) support + uid: blazor/security/gdpr - name: Server-side and Blazor Web App additional scenarios uid: blazor/security/additional-scenarios - name: State management