MVC 5 Seed-Benutzer und -Rollen

94

Ich habe mit der neuen MVC 5 herumgespielt, ich habe einige Modelle, Controller und Ansichten eingerichtet, die mit Code First Migrations eingerichtet wurden.

Meine Frage ist, wie ich Benutzer und Rollen setze. Ich setze derzeit einige Referenzdaten in meine Seed-Methode in Configuration.cs. Es scheint mir jedoch, dass die Benutzer- und Rollentabellen erst erstellt werden, wenn etwas zuerst auf den AccountController trifft.

Ich habe derzeit zwei Verbindungszeichenfolgen, damit ich meine Daten von meiner Authentifizierung in verschiedene Datenbanken trennen kann.

Wie kann ich die Tabellen für Benutzer, Rollen usw. zusammen mit meinen anderen Tabellen füllen? Und nicht, wenn der Account Controller getroffen wird?

MrBeanzy
quelle

Antworten:

181

Hier ist ein Beispiel für einen üblichen Seed-Ansatz:

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");
    }
}

Ich habe den Paketmanager "Update-Datenbank" verwendet. DB und alle Tabellen wurden erstellt und mit Daten versehen.

Valin
quelle
3
Zur Seed-Methode der Konfigurationsklasse. Die Konfiguration ist der Standardklassenname für Aktivierungsmigrationen, Sie können ihn jedoch ändern.
Valin
3
Sie sollten "enable-migrations" in der Paketmanagerkonsole verwenden. Es wird eine Konfigurationsklasse mit Seed-Methode für Sie erstellt.
Valin
4
@Zapnologica Migrations ist so einfach zu bedienen. Außerdem können Sie Ihre Tabellen bearbeiten, ohne Ihre Tabellen neu erstellen zu müssen. Es gibt nur drei Befehle, mit denen Sie sich mit der Verwendung der NuGet Package Manager-Konsole vertraut machen müssen. Enable-Migrations, Add-Migration & Update-Datenbank. Einfach peazy.
Yardpenalty.com
10
Ich habe diesen Code buchstäblich kopiert und in meine Seed-Methode in einer neuen mvc 5-Webanwendung eingefügt und dann "update-database" in der Paketmanagerkonsole ausgeführt. Es fügt die Rolle hinzu (ich kann sie in der AspNetRoles-Tabelle sehen), aber wenn es um den Vorgesetzten geht. AddToRole (user.Id, "AppAdmin") erhalte ich die Fehlermeldung "UserId not found". Wenn Sie eine Idee haben, was mir fehlt, würde ich die Informationen sehr schätzen.
Tom Regan
2
Vermisst context.Users.Add(user);zwischen manager.Create(user, "ChangeItAsap!");und manager.AddToRole(user.Id, "AppAdmin");. Neugeborene Benutzer haben also keine User.Id.
ApceH Heuchler
15

Es ist eine kleine Ergänzung, aber für jeden, der die "Benutzer-ID nicht gefunden" hat. Nachricht beim Versuch zu säen: (Tom Regan hatte diese Frage in den Kommentaren, und ich war selbst eine Weile daran festgehalten)

Dies bedeutet, dass manager.Create (Benutzer "ChangeItAsap!") Nicht erfolgreich war. Dies mag einen anderen Grund haben, aber für mich war es, weil mein Passwort nicht erfolgreich validiert wurde.

Ich hatte einen benutzerdefinierten Passwortvalidator, der beim Seeding der Datenbank nicht aufgerufen wurde, sodass die von mir verwendeten Validierungsregeln (Mindestlänge 4 statt Standard 6) nicht zutrafen. Stellen Sie sicher, dass Ihr Passwort (und alle anderen Felder) die Validierung besteht.

Kevin
quelle
7
Dies hat mir geholfen, da ich das Problem "Benutzer-ID nicht gefunden" hatte. Ich habe es geschafft, es mit dem folgenden Code aufzuspüren: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
Steve Wilford
Dieser Kommentar ist ausgezeichnet und gab mir "Benutzername Demo Benutzer ist ungültig, kann nur Buchstaben oder Ziffern enthalten." anstatt nur mehrdeutig mit einer fehlenden Benutzer-
ID zu
Ich habe festgestellt, dass meine Passwortüberprüfungsregel auch nicht funktioniert.
user1686407
14

Dies ist meine Methode basierend auf der Valin-Antwort. Ich habe Rollen in db hinzugefügt und ein Kennwort für den Benutzer hinzugefügt. Dieser Code wird in der Seed()Methode unter Migrations> Configurations.cs abgelegt .

// 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
quelle
6

Hier habe ich eine sehr einfache, saubere und reibungslose Lösung.

 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);
    }
Herr Tangjai
quelle
1
Coole Sache, aber du hast eine wichtige Sache verpasst. Sie müssen user.SecurityStamp = Guid.NewGuid (). ToString () hinzufügen, sonst wird beim Anmelden eine Fehlermeldung angezeigt.
Wirbel weiß
Vielen Dank. Ich habe diese Funktion nicht verwendet, aber ich habe sie meiner Antwort hinzugefügt.
Herr Tangjai
3
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
quelle
1
Ich habe meinen ApplicationUser so angepasst, dass er eine int-typisierte ID-Eigenschaft hat. Ihr Ansatz ist der einzige, den ich mit meinem benutzerdefinierten Benutzer und RoleStores arbeiten kann, danke!
Mike Devenney
1
Dieses Bit ist aus konzeptioneller Sicht völlig falsch : Task.Run(async () => { await SeedAsync(context); }).Wait();. Sie sollten lieber schreiben, SeedAsync(context).GetAwait().GetResult();was etwas besser ist.
Tanveer Badar
2

Sieht so aus, als hätten sie die Funktionsweise der Authentifizierung in MVC5 geändert. Meine Global.asax.cs wurde wie folgt geändert:

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
quelle
9
Diese Antwort ist nicht mehr relevant, da sich die ASP.NET-Identitäts-API geändert hat.
Josh McKearin
@ Josh McKearin Hast du eine bessere Lösung? Bitte teilen
Victor.Uduak
2

Schreiben Sie diesen Code in Ihre Migrationskonfiguration.

Hinweis: Verwenden Sie ApplicationDbContext in der Konfigurationsklasse.

    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
quelle