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é?

MrBeanzy
la source

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.

Valin
la source
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.

Kevin
la source
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 == "[email protected]"))
    {
        var user = new ApplicationUser
        {
             UserName = "[email protected]",
             Email = "[email protected]",
             PasswordHash = PasswordHash.HashPassword("123456")
         };

         UserManager.Create(user);
         UserManager.AddToRole(user.Id, Const.getRoles()[0]);
    }
Vasil Valchev
la source
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);
    }
Monsieur Tangjai
la source
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 = "[email protected]",
      EmailConfirmed = true,
      PhoneNumber = "0123456789",
      PhoneNumberConfirmed = true
    };

    await userManager.CreateAsync(user, "****");
    await userManager.AddToRoleAsync(user.Id, ApplicationRole.AdminRoleName);
  }
}
Shimmy Weitzhandler
la source
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();
        }
    }
}
MrBeanzy
la source
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" }
            );


    }
}
FatalMan
la source