MVC 5 Pengguna dan Peran Seed

95

Saya telah bermain-main dengan MVC 5 baru, saya memiliki beberapa model, pengontrol, dan pengaturan tampilan menggunakan migrasi kode pertama.

Pertanyaan saya adalah bagaimana cara memasukkan pengguna dan peran? Saat ini saya memasukkan beberapa data referensi dalam metode Seed saya di Configuration.cs. Namun menurut saya, tabel pengguna dan peran tidak dibuat hingga sesuatu yang pertama mengenai AccountController.

Saat ini saya memiliki dua string koneksi sehingga saya dapat memisahkan data saya dari otentikasi saya ke dalam database yang berbeda.

Bagaimana cara agar tabel pengguna, peran, dll. Terisi bersama dengan yang lain? Dan bukan saat pengontrol akun dipukul?

MrBeanzy
sumber

Jawaban:

182

Berikut adalah contoh pendekatan Seed biasa:

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

Saya menggunakan manajer paket "update-database". DB dan semua tabel dibuat dan diunggulkan dengan data.

Valin
sumber
3
Untuk metode Seed dari kelas Konfigurasi. Konfigurasi adalah nama kelas default untuk enable-migrations, tetapi Anda dapat mengubahnya.
Berlaku
3
Anda harus menggunakan 'enable-migrations'in konsol pengelola paket. Ini akan membuat kelas konfigurasi dengan metode seed untuk Anda.
Berlaku
4
@Zapnologica Migrations sangat mudah digunakan. Ini juga memungkinkan Anda untuk mengedit tabel Anda tanpa membuat ulang tabel Anda. Hanya ada tiga perintah yang Anda butuhkan untuk membiasakan diri Anda menggunakan Konsol Pengelola Paket NuGet. Aktifkan-Migrasi, Tambah-Migrasi, & perbarui-database. Mudah sekali.
yardpenalty.com
10
Saya benar-benar menyalin dan menempel kode ini ke metode Seed saya di aplikasi web mvc 5 baru, dan kemudian menjalankan "update-database" di konsol manajer paket. Ia menambahkan peran (saya bisa melihatnya di tabel AspNetRoles), tetapi ketika datang ke manajer lini.AddToRole (user.Id, "AppAdmin") Saya mendapatkan pesan kesalahan "UserId tidak ditemukan." Jika Anda tahu apa yang saya lewatkan, saya akan sangat menghargai informasinya.
Tom Regan
2
Terlewat context.Users.Add(user);antara manager.Create(user, "ChangeItAsap!");dan manager.AddToRole(user.Id, "AppAdmin");. Jadi pengguna yang baru lahir belum memiliki User.Id.
ApceH Hypocrite
15

Ini tambahan kecil, tetapi untuk siapa pun yang memiliki "UserId tidak ditemukan". pesan ketika mencoba untuk seed: (Tom Regan memiliki pertanyaan ini di komentar, dan saya terjebak di dalamnya sendiri untuk sementara waktu)

Ini berarti bahwa manager.Create (pengguna, "ChangeItAsap!") Tidak berhasil. Ini mungkin memiliki alasan yang berbeda, tetapi bagi saya itu karena kata sandi saya tidak berhasil validasinya.

Saya memiliki validator kata sandi khusus, yang tidak dipanggil saat melakukan seeding database, jadi aturan validasi yang saya gunakan (minlength 4 bukannya default 6) tidak berlaku. Pastikan kata sandi Anda (dan semua bidang lain dalam hal ini) melewati validasi.

Kevin
sumber
7
Ini membantu saya karena saya mengalami masalah "UserId tidak ditemukan". Saya berhasil melacaknya dengan kode berikut: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
Steve Wilford
Komentar itu luar biasa, memberi saya 'Nama pengguna Pengguna Demo tidak valid, hanya dapat berisi huruf atau angka.' bukannya gagal secara ambigu dengan userId yang hilang
dougajmcdonald
Saya menemukan aturan validasi kata sandi saya tidak berfungsi juga, tahu?
pengguna1686407
15

Ini adalah metode saya berdasarkan jawaban Valin, saya telah menambahkan peran dalam db dan menambahkan kata sandi untuk pengguna. Kode ini ditempatkan dalam Seed()metode di Migration> 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
sumber
6

Di sini saya punya solusi yang sangat mudah, bersih dan halus.

 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);
    }
Tuan Tangjai
sumber
1
Hal yang keren, tapi kamu melewatkan hal yang penting. Anda harus menambahkan user.SecurityStamp = Guid.NewGuid (). ToString () atau Anda akan mendapatkan error saat login.
eddy white
Terima kasih. Saya tidak menggunakan fitur itu tetapi saya telah menambahkannya ke jawaban saya.
Tn. 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
sumber
1
Saya menyesuaikan ApplicationUser saya agar memiliki properti ID yang diketik int. Pendekatan Anda adalah satu-satunya yang bisa saya lakukan dengan Pengguna dan RoleStores kustom saya, terima kasih!
Mike Devenney
1
Bit ini benar-benar tidak benar dari sudut pandang konseptual: Task.Run(async () => { await SeedAsync(context); }).Wait();. Anda sebaiknya menulis SeedAsync(context).GetAwait().GetResult();yang sedikit lebih baik.
Tanveer Badar
2

Sepertinya mereka mengubah cara kerja otentikasi di MVC5, mengubah Global.asax.cs saya menjadi yang berikut berhasil!

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
sumber
9
Jawaban ini tidak lagi relevan karena ASP.NET Identity API telah berubah.
Josh McKearin
@ Josh McKearin Apakah Anda memiliki solusi yang lebih baik? tolong bagikan
Victor.Uduak
2

tulis kode ini di Konfigurasi Migrasi Anda.

catatan: Gunakan ApplicationDbContext di Kelas Konfigurasi.

    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
sumber