Vue d’ensemble des API de consommateur pour ASP.NET Core

Les interfaces IDataProtectionProvider et IDataProtector sont les interfaces de base par lesquelles les consommateurs utilisent le système de protection des données. Elles se situent dans le package Microsoft.AspNetCore.DataProtection.Abstractions.

IDataProtectionProvider

L’interface du fournisseur représente la racine du système de protection des données. Elle ne peut pas être utilisée directement pour protéger ou annuler la protection des données. Au lieu de cela, le consommateur doit obtenir une référence à un IDataProtector en appelant IDataProtectionProvider.CreateProtector(purpose), où l’objectif est une chaîne qui décrit le cas d’usage du consommateur prévu. Pour plus d’informations sur l’intention de ce paramètre et sur la façon de choisir une valeur appropriée, consultez Chaînes d’objectif.

IDataProtector

L’interface de protection est retournée par un appel à CreateProtector, et c’est cette interface que les consommateurs peuvent utiliser pour effectuer des opérations de protection et de non-protection.

Pour protéger un élément de données, transmettez les données à la méthode Protect. L’interface de base définit une méthode qui convertit octet[] -> octet[], mais il existe également une surcharge (fournie sous forme de méthode d’extension) qui convertit chaîne -> chaîne. La sécurité offerte par les deux méthodes est identique, le développeur doit choisir la surcharge la plus pratique pour son cas d’usage. Quelle que soit la surcharge choisie, la valeur retournée par la méthode Protect est désormais protégée (chiffrée et inviolable) et l’application peut l’envoyer à un client non approuvé.

Pour annuler la protection d’un élément de données précédemment protégé, transmettez les données protégées à la méthode Unprotect. (Il existe des surcharges basées sur des octets[] et des chaînes pour les développeurs.) Si la charge utile protégée a été générée par un appel antérieur à Protect sur ce même IDataProtector, la méthode Unprotect retourne la charge utile non protégée d’origine. Si la charge utile protégée a été falsifiée ou a été produite par un autre IDataProtector, la méthode Unprotect lancera CryptographicException.

Le concept de IDataProtector similaire et de différent renvoie au concept d’objectif. Si deux instances IDataProtector ont été générées à partir de la même racine IDataProtectionProvider , mais via des chaînes d’objectif différentes dans l’appel à IDataProtectionProvider.CreateProtector, elles sont considérées comme des protecteurs différents, et l’une ne peut pas déprotéger les charges utiles générées par l’autre.

Utilisation de ces interfaces

Pour un composant compatible avec l’injection de dépendances, l’utilisation prévue est que le composant prend un paramètre IDataProtectionProvider dans son constructeur et que le système d’injection de dépendances fournit automatiquement ce service lorsque le composant est instancié.

Notes

Certaines applications (telles que les applications console ou les applications ASP.NET 4.x) peuvent ne pas être compatible avec l’injection de dépendances et ne peuvent donc pas utiliser le mécanisme décrit ici. Pour ces scénarios, consultez le document Scénarios non compatibles avec l’injection de dépendances pour plus d’informations sur l’obtention d’un instance d’un fournisseur IDataProtection sans passer par l’injection de dépendances.

L'exemple suivant illustre les trois concepts :

  1. Ajouter le système de protection des données au conteneur de service,

  2. Utiliser l’injection de dépendances pour recevoir une instance d’un IDataProtectionProvider, et

  3. Créer un IDataProtector à partir d’un IDataProtectionProvider et l’utiliser pour protéger et annuler la protection des données.

Application console

using System;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main(string[] args)
    {
        // add data protection services
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection();
        var services = serviceCollection.BuildServiceProvider();

        // create an instance of MyClass using the service provider
        var instance = ActivatorUtilities.CreateInstance<MyClass>(services);
        instance.RunSample();
    }

    public class MyClass
    {
        IDataProtector _protector;

        // the 'provider' parameter is provided by DI
        public MyClass(IDataProtectionProvider provider)
        {
            _protector = provider.CreateProtector("Contoso.MyClass.v1");
        }

        public void RunSample()
        {
            Console.Write("Enter input: ");
            string input = Console.ReadLine();

            // protect the payload
            string protectedPayload = _protector.Protect(input);
            Console.WriteLine($"Protect returned: {protectedPayload}");

            // unprotect the payload
            string unprotectedPayload = _protector.Unprotect(protectedPayload);
            Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
        }
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter input: Hello world!
 * Protect returned: CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ
 * Unprotect returned: Hello world!
 */

Application web

Appelez AddDataProtection(IServiceCollection, Action<DataProtectionOptions>) dans Program.cs :

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDataProtection();

var app = builder.Build();

Le code surligné suivant montre comment utiliser IDataProtector dans un contrôleur :

public class HomeController : Controller
{
    private readonly IDataProtector _dataProtector;

    public HomeController(IDataProtectionProvider dataProtectionProvider)
    {
        _dataProtector = dataProtectionProvider.CreateProtector("HomeControllerPurpose");
    }

    // ...

    public IActionResult Privacy()
    {
        // The original data to protect
        string originalData = "original data";

        // Protect the data (encrypt)
        string protectedData = _dataProtector.Protect(originalData);
        Console.WriteLine($"Protected Data: {protectedData}");

        // Unprotect the data (decrypt)
        string unprotectedData = _dataProtector.Unprotect(protectedData);
        Console.WriteLine($"Unprotected Data: {unprotectedData}");

        return View();
    }
    
    // ...

Le package Microsoft.AspNetCore.DataProtection.Abstractions contient une méthode d’extension GetDataProtector pour les développeurs. Il encapsule en tant qu’opération unique à la fois la récupération d’un IDataProtectionProvider à partir du fournisseur de services et l’appel de IDataProtectionProvider.CreateProtector. L'exemple suivant illustre son utilisation :

using System;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
 
public class Program
{
    public static void Main(string[] args)
    {
        // add data protection services
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection();
        var services = serviceCollection.BuildServiceProvider();
 
        // get an IDataProtector from the IServiceProvider
        var protector = services.GetDataProtector("Contoso.Example.v2");
        Console.Write("Enter input: ");
        string input = Console.ReadLine();
 
        // protect the payload
        string protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");
 
        // unprotect the payload
        string unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
    }
}

Conseil

Les instances de IDataProtectionProvider et IDataProtector sont thread-safe pour plusieurs appelants. Il est prévu qu’une fois qu’un composant obtient une référence à un IDataProtector via un appel vers CreateProtector, il utilise cette référence pour plusieurs appels vers Protect et Unprotect. Un appel vers Unprotect lève CryptographicException si la charge utile protégée ne peut pas être vérifiée ou déchiffrée. Certains composants peuvent souhaiter d’ignorer les erreurs lors des opérations non-protégée ; un composant qui lit des authentifications cookiepeut gérer cette erreur et traiter la requête comme s’il n’y avait pas de cookie du tout au lieu d’échouer la demande. Les composants qui voudraient adopter ce comportement devraient spécifiquement intercepter les CryptographicException au lieu d'avaler toutes les exceptions.