Quel est l'objectif de la colonne ConcurrencyStamp
de la table AspNetUsers
de la nouvelle identité ASP.NET MVC 6?
Voici le schéma de base de données de la table AspNetUsers
:
C'est aussi là dans la table AspNetRoles
:
Si je me souviens bien, l'identité ASP.NET MVC 5 n'y figurait pas.
Ce que j'ai remarqué jusqu'à présent, c'est qu'il semble avoir les valeurs GUID telles qu'elles sont définies avec le code suivant:
/// <summary>
/// A random value that must change whenever a user is persisted to the store
/// </summary>
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();
Mais cette documentation ne me suffit pas pour comprendre dans quelles situations elle est utilisée.
En tant que nom, il est utilisé pour éviter les conflits de mise à jour par accès simultané.
Par exemple, il y a un utilisateurA nommé Peter dans la base de données 2 administrateurs ouvrent la page d'édition de UserA et souhaitent mettre à jour cet utilisateur.
Que se passerait-il s'il n'y avait pas de ConcurrencyStamp si la mise à jour de Admin_1 était remplacée par celle de Admin_2 . Mais puisque nous avons ConcurrencyStamp, lorsque Admin_1/Admin_2 charge la page, le tampon est chargé. Lors de la mise à jour des données, ce tampon sera également modifié . L’étape 5 consisterait donc maintenant en une exception système en indiquant à Admin_2 que cet utilisateur avait déjà été mis à jour, car ConcurrencyStamp est différent de celui qu’il a chargé.
À partir du code source lui-même
/// <summary>
/// A random value that should change whenever a role is persisted to the store
/// </summary>
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();
En gros, voyez-le comme il est nommé. Un tampon utilisé pour identifier la version actuelle des données. Si vous le changez, le tampon l'est aussi.
Ainsi, si deux mises à jour simultanées arrivent en même temps, elles doivent avoir le même tampon ou l’un d’eux devrait être jeté.
D'où le nom, ConcurrencyStamp
.
Pour donner suite à la réponse de Maxime:
Si vous regardez l'implémentation d'IdentityDbContext dans la méthode OnModelCreating (), vous trouverez:
builder.Entity<TUser>(b =>
{
....
b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();
....
et dans la méthode UserStore.UpdateAsync (...):
Context.Update(user);
try
{
await SaveChanges(cancellationToken);
}
catch (DbUpdateConcurrencyException)
{
return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
}
Donc, il fait bien ce qu'il est censé faire: empêcher les mises à jour simultanées sur un objet utilisateur. Le jeton est simplement utilisé "sous le capot" dans le module ASP Identity EntityFramework. En gros, si une mise à jour simultanée d'un objet utilisateur se produit, le contexte de base de données lève l'exception DbUpdateConcurrencyException.
Il est également important de comprendre qu’il s’agit en fait d’une fonctionnalité EF Core, le schéma d’Identity définissant simplement la colonne à utiliser comme colonne de simultanéité, sans pour autant la demander ni l’utiliser en interne.
Il n'y a pas de logique de comparaison en cours inside Identity codebase - c'est uniquement lorsque EFCore va réellement le sauvegarder qu'il entre en jeu.
https://docs.Microsoft.com/en-us/ef/core/modeling/concurrency