Utilisateurs et rôles MVC 5 Seed


95

J'ai joué avec le nouveau MVC 5, j'ai quelques modèles, contrôleurs et vues configurés à l'aide de premières migrations de code.

Ma question est de savoir comment générer des utilisateurs et des rôles? J'encore actuellement des données de référence dans ma méthode Seed dans Configuration.cs. Mais il me semble que les tables d'utilisateurs et de rôles ne sont pas créées avant que quelque chose n'atteigne le AccountController.

J'ai actuellement deux chaînes de connexion afin de pouvoir séparer mes données de mon authentification dans différentes bases de données.

Comment puis-je faire remplir les tables des utilisateurs, des rôles, etc. avec mes autres? Et pas lorsque le contrôleur de compte est touché?


Réponses:


182

Voici un exemple d'approche Seed habituelle:

protected override void Seed(SecurityModule.DataContexts.IdentityDb context)
{
    if (!context.Roles.Any(r => r.Name == "AppAdmin"))
    {
        var store = new RoleStore<IdentityRole>(context);
        var manager = new RoleManager<IdentityRole>(store);
        var role = new IdentityRole { Name = "AppAdmin" };

        manager.Create(role);
    }

    if (!context.Users.Any(u => u.UserName == "founder"))
    {
        var store = new UserStore<ApplicationUser>(context);
        var manager = new UserManager<ApplicationUser>(store);
        var user = new ApplicationUser {UserName = "founder"};

        manager.Create(user, "ChangeItAsap!");
        manager.AddToRole(user.Id, "AppAdmin");
    }
}

J'ai utilisé le gestionnaire de paquets "update-database". La base de données et toutes les tables ont été créées et remplies de données.


3
À la méthode Seed de la classe Configuration. La configuration est le nom de classe par défaut pour les migrations d'activation, mais vous pouvez le modifier.
Valin

3
Vous devez utiliser 'enable-migrations' dans la console du gestionnaire de packages. Il créera pour vous une classe de configuration avec la méthode seed.
Valin

4
@Zapnologica Migrations est si facile à utiliser. Il vous permet également de modifier vos tableaux sans recréer vos tableaux. Vous n'avez besoin que de trois commandes pour vous familiariser avec l'utilisation de la console NuGet Package Manager. Enable-Migrations, Add-Migration et update-database. Facile paisible.
yardpenalty.com

10
J'ai littéralement copié et collé ce code dans ma méthode Seed dans une nouvelle application Web mvc 5, puis j'ai exécuté "update-database" dans la console du gestionnaire de paquets. Il ajoute le rôle (je peux le voir dans la table AspNetRoles), mais en ce qui concerne le gestionnaire de ligne .AddToRole (user.Id, "AppAdmin"), j'obtiens le message d'erreur "UserId not found." Si vous avez une idée de ce qui me manque, j'apprécierais beaucoup l'information.
Tom Regan

2
Manqué context.Users.Add(user);entre manager.Create(user, "ChangeItAsap!");et manager.AddToRole(user.Id, "AppAdmin");. Donc, l'utilisateur nouveau-né n'a pas User.Id.
ApceH Hypocrite

15

C'est un petit ajout, mais à toute personne ayant le "UserId not found". message en essayant de semer: (Tom Regan avait cette question dans les commentaires, et je suis resté coincé moi-même pendant un moment)

Cela signifie que manager.Create (utilisateur, "ChangeItAsap!") N'a pas réussi. Cela peut avoir une raison différente, mais pour moi c'était parce que mon mot de passe ne réussissait pas sa validation.

J'avais un passwordvalidator personnalisé, qui n'était pas appelé lors de l'amorçage de la base de données, donc les règles de validation auxquelles j'étais utilisé (minlength 4 au lieu de default 6) ne s'appliquaient pas. Assurez-vous que votre mot de passe (et tous les autres champs d'ailleurs) passe la validation.


7
Cela m'a aidé car j'avais le problème "UserId not found". J'ai réussi à le retrouver avec le code suivant: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
Steve Wilford

Ce commentaire est excellent, il m'a donné "Le nom d'utilisateur de démonstration est invalide, ne peut contenir que des lettres ou des chiffres." au lieu d'échouer de façon ambiguë avec un userId manquant
dougajmcdonald

J'ai trouvé que ma règle de validation de mot de passe ne fonctionnait pas trop, une idée?
user1686407

15

Ceci est ma méthode basée sur la réponse Valin, j'ai ajouté des rôles dans la base de données et un mot de passe ajouté pour l'utilisateur. Ce code est placé dans Seed()method dans Migrations> Configurations.cs.

// role (Const.getRoles() return string[] whit all roles)

    var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
    for (int i = 0; i < Const.getRoles().Length; i++)
    {
        if (RoleManager.RoleExists(Const.getRoles()[i]) == false)
        {
            RoleManager.Create(new IdentityRole(Const.getRoles()[i]));
        }
    }

// user

    var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
    var PasswordHash = new PasswordHasher();
    if (!context.Users.Any(u => u.UserName == "admin@admin.net"))
    {
        var user = new ApplicationUser
        {
             UserName = "admin@admin.net",
             Email = "admin@admin.net",
             PasswordHash = PasswordHash.HashPassword("123456")
         };

         UserManager.Create(user);
         UserManager.AddToRole(user.Id, Const.getRoles()[0]);
    }

6

Ici, j'ai une solution très simple, propre et fluide.

 protected override void Seed(UserContext context)
    { 
        //Step 1 Create the user.
        var passwordHasher = new PasswordHasher();
        var user = new IdentityUser("Administrator");
        user.PasswordHash = passwordHasher.HashPassword("Admin12345");
        user.SecurityStamp = Guid.NewGuid().ToString();

        //Step 2 Create and add the new Role.
        var roleToChoose = new IdentityRole("Admin");
        context.Roles.Add(roleToChoose);

        //Step 3 Create a role for a user
        var role = new IdentityUserRole();
        role.RoleId = roleToChoose.Id;
        role.UserId = user.Id;

         //Step 4 Add the role row and add the user to DB)
        user.Roles.Add(role);
        context.Users.Add(user);
    }

1
Chose cool, mais tu as raté une chose importante. Vous devez ajouter user.SecurityStamp = Guid.NewGuid (). ToString () ou vous obtiendrez une erreur lors de la connexion.
blanc tourbillon du

THX. Je n'ai pas utilisé cette fonctionnalité mais je l'ai ajoutée à ma réponse.
Mr Tangjai

4
protected override void Seed(ApplicationDbContext context)
{
  SeedAsync(context).GetAwaiter().GetResult();
}

private async Task SeedAsync(ApplicationDbContext context)
{
  var userManager = new ApplicationUserManager(new UserStore<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context));
  var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole, int, ApplicationUserRole>(context));

  if (!roleManager.Roles.Any())
  {
    await roleManager.CreateAsync(new ApplicationRole { Name = ApplicationRole.AdminRoleName });
    await roleManager.CreateAsync(new ApplicationRole { Name = ApplicationRole.AffiliateRoleName });
  }

  if (!userManager.Users.Any(u => u.UserName == "shimmy"))
  {
    var user = new ApplicationUser
    {
      UserName = "shimmy",
      Email = "shimmy@gmail.com",
      EmailConfirmed = true,
      PhoneNumber = "0123456789",
      PhoneNumberConfirmed = true
    };

    await userManager.CreateAsync(user, "****");
    await userManager.AddToRoleAsync(user.Id, ApplicationRole.AdminRoleName);
  }
}

1
J'ai personnalisé mon ApplicationUser pour avoir une propriété ID typée int. Votre approche est la seule que je puisse utiliser avec mes User and RoleStores personnalisés, merci!
Mike Devenney

1
Ce bit est tout à fait incorrect d'un point de vue conceptuel: Task.Run(async () => { await SeedAsync(context); }).Wait();. Vous devriez plutôt écrire SeedAsync(context).GetAwait().GetResult();ce qui est légèrement meilleur.
Tanveer Badar

2

On dirait qu'ils changent la façon dont l'authentification fonctionne dans MVC5, ont changé mon Global.asax.cs comme suit a fait l'affaire!

using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

using System.Threading.Tasks;
using MvcAuth.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System.Threading;
using Microsoft.AspNet.Identity.EntityFramework;

namespace MvcAuth
{
    public class MvcApplication : System.Web.HttpApplication
    {
        async Task<bool> AddRoleAndUser()
        {
            AuthenticationIdentityManager IdentityManager = new AuthenticationIdentityManager(
                new IdentityStore(new ApplicationDbContext()));

            var role = new Role("Role1");
            IdentityResult result = await IdentityManager.Roles.CreateRoleAsync(role, CancellationToken.None);
            if (result.Success == false)
                return false;

            var user = new ApplicationUser() { UserName = "user1" };
            result = await IdentityManager.Users.CreateLocalUserAsync(user, "Password1");
            if (result.Success == false)
                return false;

            result = await IdentityManager.Roles.AddUserToRoleAsync(user.Id, role.Id, CancellationToken.None);
            return result.Success;
        }

        protected async void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            bool x = await AddRoleAndUser();
        }
    }
}

9
Cette réponse n'est plus pertinente car l'API d'identité ASP.NET a changé.
Josh McKearin

@Josh McKearin Avez-vous une meilleure solution? s'il vous plaît partager
Victor.Uduak

2

écrivez ce code dans votre configuration de migration.

Remarque: utilisez ApplicationDbContext dans la classe de configuration.

    internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = false;
    }

    protected override void Seed(ApplicationDbContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data.
                   context.Roles.AddOrUpdate(p =>
            p.Id,
                new IdentityRole { Name = "Admins"},
                new IdentityRole { Name = "PowerUsers" },
                new IdentityRole { Name = "Users" },
                new IdentityRole { Name = "Anonymous" }
            );


    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.