MVC 5シードユーザーとロール


94

私は新しいMVC 5で遊んでいますが、コードファーストマイグレーションを使用して、いくつかのモデル、コントローラー、ビューをセットアップしています。

私の質問は、ユーザーとロールをシードする方法ですか?現在、Configuration.csのSeedメソッドに参照データをシードしています。しかし、何かが最初にAccountControllerに到達するまで、ユーザーテーブルとロールテーブルは作成されないように見えます。

現在、2つの接続文字列を持っているので、データを認証から別のデータベースに分離できます。

他のユーザーと共にユーザー、ロールなどのテーブルを作成するにはどうすればよいですか?そして、アカウントコントローラーがヒットしたときではありませんか?


回答:


181

通常のシードアプローチの例を次に示します。

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

パッケージマネージャー「update-database」を使用しました。DBとすべてのテーブルが作成され、データがシードされました。


3
ConfigurationクラスのSeedメソッドへ。構成はenable-migrationsのデフォルトのクラス名ですが、変更することもできます。
ヴァリン2014年

3
パッケージマネージャーコンソールで 'enable-migrations'を使用する必要があります。それはあなたのためにシードメソッドで設定クラスを作成します。
Valin

4
@Zapnologica Migrationsはとても使いやすいです。また、テーブルを再作成せずにテーブルを編集することもできます。NuGetパッケージマネージャーコンソールの使用に慣れるために必要なコマンドは3つだけです。移行の有効化、移行の追加、およびデータベースの更新を有効にします。イージーピージー。
yardpenalty.com 2014年

10
このコードを文字通り新しいmvc 5 Webアプリケーションのシードメソッドにコピーして貼り付け、パッケージマネージャーコンソールで "update-database"を実行しました。役割を追加します(AspNetRolesテーブルで確認できます)が、manager.AddToRole(user.Id、 "AppAdmin")の行になると、 "UserId not found"というエラーメッセージが表示されます。私が見逃しているものが何かあれば、情報をいただければ幸いです。
Tom Regan、

2
とのcontext.Users.Add(user);間にmanager.Create(user, "ChangeItAsap!");ありませんmanager.AddToRole(user.Id, "AppAdmin");でした。したがって、生まれたばかりのユーザーはUser.Idを持っていません。
ApceH Hypocrite 2017

15

これは小さな追加ですが、「UserId not found」を持っている人には追加されます。シードしようとしたときのメッセージ:(トム・リーガンはコメントにこの質問があり、私はしばらく私自身にこだわっていました)

これは、manager.Create(user、 "ChangeItAsap!")が成功しなかったことを意味します。これには別の理由があるかもしれませんが、私にとっては、私のパスワードが検証に成功しなかったことが原因でした。

データベースをシードするときに呼び出されなかったカスタムpasswordvalidatorがあったため、これまで使用していた検証ルール(デフォルト6ではなく最小長4)は適用されませんでした。パスワード(およびそのことに関する他のすべてのフィールド)が検証に合格していることを確認してください。


7
「UserId not found」の問題が発生していたため、これは私に役立ちました。私は次のコードでそれを追跡することができました: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
スティーブウィルフォード

そのコメントは素晴らしく、それは私に「ユーザー名のデモユーザーは無効であり、文字または数字しか含めることができない」と与えました。userIdがないために曖昧に失敗するのではなく、
dougajmcdonald

パスワード検証ルールも機能しないことがわかりました。
user1686407 2016

15

これはValinの回答に基づく私の方法です。dbにロールを追加し、ユーザーのパスワードを追加しました。このコードはSeed()、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

ここに私は非常に簡単でクリーンでスムーズな解決策を持っています。

 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
クールなことですが、重要なことを逃しました。user.SecurityStamp = Guid.NewGuid()。ToString()を追加する必要があります。そうしないと、ログイン時にエラーが発生します。
エディホワイト

どうも。その機能は使用しませんでしたが、回答に追加しました。
タンジャイ氏、

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 = "shimmy@gmail.com",
      EmailConfirmed = true,
      PhoneNumber = "0123456789",
      PhoneNumberConfirmed = true
    };

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

1
ApplicationUserをカスタマイズして、int型のIDプロパティを設定しました。あなたのアプローチは私が私のカスタムのユーザーとロールストアで働くことができる唯一の方法です、ありがとう!
Mike Devenney

1
このビットは、概念的な観点からは完全に正しくありませんTask.Run(async () => { await SeedAsync(context); }).Wait();。どちらかといえば、どちらかといえばSeedAsync(context).GetAwait().GetResult();良い方を書くべきです。
Tanveer Badar

2

MVC5での認証の動作が変更されたようです。Global.asax.csを次のように変更して、トリックを実行しました。

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
ASP.NET Identity APIが変更されたため、この回答は関係ありません。
Josh McKearin 2013年

@ジョシュ・マッケリンより良い解決策はありますか?共有してください
Victor.Uduak 2017

2

このコードを移行構成に記述します。

注:構成クラスでApplicationDbContextを使用してください。

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


    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.