Użytkownicy i role nasion MVC 5

95

Bawiłem się nowym MVC 5, mam kilka modeli, konfiguracji kontrolera i widoków przy użyciu migracji najpierw kodu.

Moje pytanie brzmi: jak zasiać użytkowników i role? Obecnie umieszczam pewne dane referencyjne w mojej metodzie Seed w Configuration.cs. Ale wydaje mi się, że tabele użytkowników i ról nie są tworzone, dopóki coś nie trafi do AccountController.

Obecnie mam dwa parametry połączenia, więc mogę oddzielić moje dane z mojego uwierzytelnienia do różnych baz danych.

Jak mogę sprawić, by tabele użytkowników, ról itp. Zapełniły się razem z innymi? A nie po trafieniu w kontroler konta?

MrBeanzy
źródło

Odpowiedzi:

183

Oto przykład zwykłego podejścia do nasion:

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

Użyłem menedżera pakietów "update-database". Baza danych i wszystkie tabele zostały utworzone i wypełnione danymi.

Valin
źródło
3
Do metody Seed klasy Configuration. Konfiguracja to domyślna nazwa klasy dla migracji włączających, ale można ją zmienić.
Valin
3
Powinieneś użyć opcji „enable-migrations” w konsoli menedżera pakietów. Stworzy dla Ciebie klasę konfiguracyjną z metodą seed.
Valin
4
@Zapnologica Migrations jest bardzo łatwy w użyciu. Umożliwia także edycję tabel bez ponownego tworzenia tabel. Istnieją tylko trzy polecenia, które musisz zapoznać się z używaniem konsoli Menedżera pakietów NuGet. Enable-Migrations, Add-Migration i Update-Database. Łatwy peazy.
yardpenalty.com
10
Dosłownie skopiowałem i wkleiłem ten kod do mojej metody Seed w nowej aplikacji internetowej mvc 5, a następnie uruchomiłem aktualizację bazy danych w konsoli menedżera pakietów. Dodaje rolę (widzę to w tabeli AspNetRoles), ale jeśli chodzi o menedżera liniowego.AddToRole (user.Id, „AppAdmin”) pojawia się komunikat o błędzie „UserId not found”. Jeśli masz pojęcie, czego mi brakuje, będę bardzo wdzięczny za informacje.
Tom Regan,
2
Nieodebrane context.Users.Add(user);między manager.Create(user, "ChangeItAsap!");a manager.AddToRole(user.Id, "AppAdmin");. Tak więc nowonarodzony użytkownik nie ma User.Id.
ApceH Hypocrite
15

To niewielki dodatek, ale dla każdego, kto ma „UserId not found”. wiadomość przy próbie seedowania: (Tom Regan miał to pytanie w komentarzach i sam na to utknąłem)

Oznacza to, że manager.Create (użytkownik, "ChangeItAsap!") Nie powiodło się. Może to mieć inny powód, ale dla mnie było to spowodowane tym, że moje hasło nie przeszło pomyślnie weryfikacji.

Miałem niestandardowy walidator haseł, który nie był wywoływany podczas inicjowania bazy danych, więc reguły walidacji, do których byłem używany (minlength 4 zamiast domyślnego 6) nie miały zastosowania. Upewnij się, że Twoje hasło (i wszystkie inne pola w tym zakresie) przechodzi weryfikację.

Kevin
źródło
7
Pomogło mi to, ponieważ pojawił się problem „Nie znaleziono identyfikatora użytkownika”. Udało mi się to namierzyć za pomocą następującego kodu: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
Steve Wilford
Ten komentarz jest doskonały, dał mi „Nazwa użytkownika Demo Użytkownik jest nieprawidłowy, może zawierać tylko litery lub cyfry”. zamiast po prostu zawodzić niejednoznacznie z brakującym
identyfikatorem użytkownika
Zauważyłem, że moja reguła sprawdzania poprawności hasła też nie działa, jakiś pomysł?
user1686407
15

To jest moja metoda oparta na odpowiedzi Valina, dodałem role w db i dodałem hasło dla użytkownika. Ten kod jest umieszczony w Seed()metodzie w 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
źródło
6

Tutaj mam bardzo łatwe, czyste i gładkie rozwiązanie.

 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);
    }
Panie Tangjai
źródło
1
Fajna rzecz, ale przegapiłeś ważną rzecz. Musisz dodać user.SecurityStamp = Guid.NewGuid (). ToString () albo pojawi się błąd przy logowaniu.
eddy white
Dzięki. Nie korzystałem z tej funkcji, ale dodałem ją do mojej odpowiedzi.
Pan 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
źródło
1
Dostosowałem mój ApplicationUser, aby miał właściwość ID wpisaną int. Twoje podejście jest jedyną metodą, z jaką mogę pracować z moimi niestandardowymi użytkownikami i sklepami ról, dzięki!
Mike Devenney
1
Ten bit jest całkowicie błędne z koncepcyjnego punktu widzenia: Task.Run(async () => { await SeedAsync(context); }).Wait();. Powinieneś raczej napisać, SeedAsync(context).GetAwait().GetResult();co jest nieznacznie lepsze.
Tanveer Badar
2

Wygląda na to, że zmieniły sposób, w jaki działa uwierzytelnianie w MVC5, zmieniły mój plik Global.asax.cs na następujący załatwił sprawę!

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
źródło
9
Ta odpowiedź nie ma już znaczenia, ponieważ interfejs API ASP.NET Identity został zmieniony.
Josh McKearin
@Josh McKearin Czy masz lepsze rozwiązanie? proszę o udostępnienie
Victor.Uduak
2

napisz ten kod w swojej konfiguracji migracji.

Uwaga: Użyj ApplicationDbContext w klasie konfiguracji.

    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
źródło