web-dev-qa-db-fra.com

MVC5: UserManager.AddToRole (): "Erreur lors de l'ajout d'un utilisateur à un rôle: ID utilisateur introuvable"?

J'ai expérimenté MVC5/EF6 et essayé la nouvelle authentification d'identité avec des migrations code-premier. Tout dans la solution est en cours de construction et je peux ajouter une Migration, mais lorsque j'exécute un update-database par le package manager console dans VS2013, mon fichier Configuration.cs ne parvient pas à traiter complètement mes données de test dans mes tables et sorties Error Adding User to Role: UserId not found.

J'ai essayé explicitement de définir un ID utilisateur et de le laisser être généré par le responsable (comme dans certains exemples), mais chaque fois, je reçois le même message d'erreur. Je sais que l'erreur échoue dans mon #region User & User Roles de mon fichier Configuration.cs, mais je ne sais pas pourquoi:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using PersonalPortfolio2.Helper;
using PersonalPortfolio2.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Diagnostics;
using System.Linq;

namespace PersonalPortfolio2.Models
{
    public sealed class Configuration : DbMigrationsConfiguration<PersonalPortfolio2.Models.ApplicationDbContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(PersonalPortfolio2.Models.ApplicationDbContext context)
        {
            BlobHelper bh = new BlobHelper();
            //LocationHelper lh = new LocationHelper();
            ApplicationDbContext db = new ApplicationDbContext();

            #region Roles
            try
            {
                List<string> myRoles = new List<string>(new string[] { "Root", "Admin", "Outsider", "Client", "Primary" });
                var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));

                foreach (string r in myRoles)
                {
                    RoleManager.Create(new IdentityRole(r));
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error Create Roles: " + ex.Message);
            }
            #endregion

            #region User & User Roles
            var store = new UserStore<ApplicationUser>(context);
            var manager = new UserManager<ApplicationUser>(store);

            List<ApplicationUser> myUsers = GetTestUsers();
            var passwordHasher = new PasswordHasher();

            foreach (var u in myUsers)
            {
                var userExists = db.Users.Where(a => a.Email == u.Email).FirstOrDefault();
                if (userExists == null)
                {
                    var user = new ApplicationUser
                    {
                        Email = u.Email,
                        PasswordHash = passwordHasher.HashPassword("P@ssword1"),
                        LockoutEnabled = false,
                        Name = u.Name,
                        Position = u.Position,
                        RegisteredDate = DateTime.Now,
                        LastVisitDate = DateTime.Now,
                        OrganizationId = u.OrganizationId,
                        ProfilePictureSrc = u.ProfilePictureSrc,
                    };

                    try
                    {
                        var userCreateResult = manager.Create(user);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Error Add User: " + ex.Message + "\n" + ex.InnerException);
                    }

                    // Add User to Roles
                    List<string> usersRoles = GetUserRoles(u.Email);
                    bool codeHit = false;
                    foreach (string role in usersRoles)
                    {
                        try
                        {
                            codeHit = true;
                            manager.AddToRole(user.Id, role);
                        }
                        catch (Exception ex)
                        {
                            // ERROR!
                            throw new Exception("Error Adding User to Role: " + ex.Message + "\n" + ex.Data + "\n" + ex.InnerException + "\nName: " + user.Name + "\nEmail: " + user.Email + "\nuser.ID: " + user.Id + "\nu.Id: " + u.Id + "\nRole: " + role + "\nCodeHit: " + codeHit);
                        }
                    }
                }

            }
            #endregion

}

            #region Helpers
            private List<ApplicationUser> GetTestUsers()
            {
                List<ApplicationUser> testUsers = new List<ApplicationUser>
                {
                    new ApplicationUser
                    {
                        Id = "1",
                        Email = "[email protected]",
                        Name = "Admin User",
                        RegisteredDate = System.DateTime.Now,
                        LastVisitDate = System.DateTime.Now,
                        Position = "Site Administrator",
                        PhoneNumber = "1234564321",
                    },
                    new ApplicationUser
                    {
                        Id = "2",
                        Email = "[email protected]",
                        Name = "James Woods",
                        RegisteredDate = System.DateTime.Now,
                        LastVisitDate = System.DateTime.Now,
                        Position = "Software Developer / Web Designer",
                        PhoneNumber = "1234567890",
                    },
                    new ApplicationUser
                    {
                        Id = "3",
                        Email = "[email protected]",
                        Name = "Tyler Perry",
                        RegisteredDate = System.DateTime.Now,
                        LastVisitDate = System.DateTime.Now,
                        Position = "Company Contact",
                        PhoneNumber = "1234567890",
                    }
                };
                return testUsers;
            }


            public List<string> GetUserRoles(string user)
            {
                List<string> myRoles = new List<string>();
                switch (user)
                {
                        //"Root", "Admin", "Outsider", "Client", "Primary"
                    case "[email protected]":
                        myRoles = new List<string>(new string[] { "Root", "Admin" });
                        break;
                    case "[email protected]":
                        myRoles = new List<string>(new string[] { "Admin" });
                        break;
                    case "[email protected]":
                        myRoles = new List<string>(new string[] { "Client", "Outsider" });
                        break;
                    default:
                        myRoles = new List<string>(new string[] {"[user] not found."});
                        break;
                }
                return myRoles;
            }
            #endregion

    }
}

Quelqu'un peut-il nous donner un aperçu de ce que je peux oublier? Pour plus de détails, ma déclaration catch actuelle affiche les éléments suivants:

Error Adding User to Role: UserId not found.
System.Collections.ListDictionaryInternal

Name: Admin User
Email: [email protected]
user.ID: 1
u.Id: 1
Role: Root
CodeHit: True

Lorsque je commente le Id = "1", explicite pour mon utilisateur administrateur, le user.ID et le u.Id deviennent: ab753316-3d7b-4f98-a13a-d19f7c926976. Je pensais que c’était peut-être le problème avec mes méthodes auxiliaires de GetTestUsers() ou GetUserRoles(u.Email), mais entre mon try/catch et la variable booléenne codeHit que j’utilise, j’ai vérifié que le problème venait certainement de manager.AddToRole(user.Id, role).

19
Analytic Lunatic

Je laisse ceci ici pour quiconque aurait pu avoir un problème similaire. J'ai eu exactement les mêmes "symptômes". Il s’avère que le problème lié au mot de passe stocké n’est pas conforme à la stratégie de mot de passe configurée (au moins un caractère majuscule, un caractère minuscule, etc.). 

Comme indiqué ci-dessous dans les commentaires et les réponses, en général, le même message d'erreur vague est émis lorsqu'une des contraintes ou des stratégies de création d'utilisateur n'est pas suivie.

Cela pourrait inclure les éléments suivants:

  • Politique de mot de passe non suivie (cela semble être la cause la plus courante)
  • Les champs obligatoires sont transmis en tant que chaînes vides/null
  • Nom d'utilisateur ou adresse électronique en double

Il existe en réalité un large éventail de problèmes pouvant provoquer cette erreur. Si ce qui précède ne résout pas votre problème, je suggère ce qui suit:

  1. Familiarisez-vous avec les règles et les règles du fournisseur d'identité tel qu'il a été configuré pour votre solution.
  2. Conformément à la réponse de @ Ted ci-dessous, tracez ou mettez un point d'arrêt sur la méthode UserManager.Create pour afficher le résultat, car cela révélera probablement la cause de votre problème.
27
Daffy Punk

La réponse de CraftBeerHipsterDude m'a aidée à trouver la réponse à la même situation que moi. Si AddToRole échoue, l'astuce consiste à examiner le résultat renvoyé par Usermanager.Create (...). Il se peut qu'il ne lise pas d'exception, mais qu'il renvoie quand même un résultat indiquant que la création a échoué. Dans mon cas c'était "Le nom d'utilisateur existe déjà".

Pour généraliser: Vérifiez les résultats des opérations précédentes pour localiser l'erreur réelle.

10
Ted

Réponse au créateur de la question: L'identifiant utilisateur ne doit pas être entré, laissez cela au framework d'entités pour le créer pour les utilisateurs. Vous essayez également de le saisir sous forme d'entier, mais l'identifiant des utilisateurs en sécurité basée sur les rôles est un GUID sous la forme d'une chaîne, il ne fonctionnerait donc pas d'essayer d'ajouter une valeur entière pour une colonne dans l'attente d'une chaîne.

Maintenant, ce n’était pas le problème pour moi, mais j’avais deux autres problèmes avec la même erreur:

J'ai essayé de comprendre ce qui me manquait mais je n'ai rien trouvé de mal.

J'ai donc utilisé une autre instance de VS en tant que débogueur du code de départ (trouvé dans un autre thread):

    if (System.Diagnostics.Debugger.IsAttached == false)
    System.Diagnostics.Debugger.Launch();

J'ai remarqué que l'utilisateur avait effectivement un identifiant lorsqu'il était ajouté au rôle . J'ai finalement pu résoudre ce problème en ajoutant un bloc catch vide .. le code ne lève pas d'exceptions à cause d'une erreur erronée et les utilisateurs sont ajoutés aux bons rôles:

    try
    {
        var newUser = userManager.FindByEmail(superuserToInsert.Email);
        userManager.AddToRole(newUser.Id, "Super users");
    }
    catch 
    {
    }

Avant d’essayer d’ajouter un utilisateur nouvellement créé à un rôle, la graine semblait annuler la création de l’utilisateur et celui-ci n’était jamais créé dans la base de données des utilisateurs.

Mais lorsque j'ai entièrement supprimé la partie d'ajout au rôle, l'utilisateur a été ajouté à la base de données et, lors de la deuxième exécution d'un code de configuration légèrement modifié, l'utilisateur pouvait être ajouté à un rôle, me laissant ainsi supposer qu'il s'agissait d'une fausse erreur. jeté .. ignorer cette fausse erreur avec le bloc catch vide semble également ignorer la restauration de la création de l'utilisateur (qui doit se produire derrière les rideaux juste avant l'ajout à la partie de rôle) conduisant à l'utilisateur existant lorsque l'ajout à la partie de rôle du code.

J'espère que ça aide quelqu'un

MODIFIER:

Ce qui précède a résolu presque tout le mal à la tête, mais j’ai remarqué que quelque 300 comptes ne pouvaient toujours pas être créés (mais aucune erreur n’était générée). Un simple FULL OUTER JOIN et un examen de la base de données utilisateur avec la table de base source me conduisent à penser que les utilisateurs avec un tiret (-) dans les colonnes de valeur pour "UserName" et "Email" ont empêché la création des utilisateurs, était le cas.

C'était une solution facile, il suffit de configurer le gestionnaire d'utilisateurs pour qu'il utilise plus que des caractères alphanumériques: (Et même si le nom de l'attribut semble pointer uniquement sur "Noms d'utilisateur", il affecte également "Email")

    var userManager = new UserManager<ApplicationUser>(userStore);

    userManager.UserValidator = new UserValidator<ApplicationUser(userManager)
    {
        AllowOnlyAlphanumericUserNames = false,
    }; 

// Miske

5
Mikael Puusaari

J'éviterais d'utiliser UserManager et RoleManager dans votre méthode Seed. Au lieu de cela, je n'utiliserais que le contexte. Quelque chose que j’utilise est le suivant qui crée un utilisateur et l’assigne à un rôle:

protected override void Seed(DbModelContext context)
{
    if (context == null)
    {
        throw new ArgumentNullException("context", "Context must not be null.");
    }

    const string UserName = "User";
    const string RoleName = "UserRole";

    var userRole = new IdentityRole { Name = RoleName, Id = Guid.NewGuid().ToString() };
    context.Roles.Add(userRole);

    var hasher = new PasswordHasher();

    var user = new IdentityUser
                   {
                       UserName = UserName,
                       PasswordHash = hasher.HashPassword(UserName),
                       Email = "[email protected]",
                       EmailConfirmed = true,
                       SecurityStamp = Guid.NewGuid().ToString()
                   };

    user.Roles.Add(new IdentityUserRole { RoleId = userRole.Id, UserId = user.Id });

    context.Users.Add(user);

    base.Seed(context);
}

Les classes Entity sont des implémentations personnalisées (parce que je voulais utiliser des GUID en tant qu'ID), mais elles dérivent des classes du framework. Avec cela, cela devrait fonctionner de la même manière si vous les modifiez dans les classes de framework appropriées.

MODIFIER

J'ai supprimé les classes personnalisées et les ai basculées vers les classes du framework, car il y avait une certaine confusion.

4
Horizon_Net

Cela a sauvé mon 2ème jour. Merci @ Daffy Punk. Dans mon cas, le problème était mot de passe. qui était "abc" avant. 

var studentPassword = "abcABC_9";
                        var user = new ApplicationUser { UserName = "abc", Email = [email protected] };
                        var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
                        var result = await UserManager.CreateAsync(user, studentPassword.ToString());
                        await UserManager.AddToRoleAsync(user.Id, "Student");
0
abdul hameed