【问题标题】:MVC 5 Seed Users and RolesMVC 5 种子用户和角色
【发布时间】:2013-10-17 07:31:36
【问题描述】:

我一直在使用新的 MVC 5,我有一些模型、控制器和视图设置使用代码优先迁移。

我的问题是如何播种用户和角色?我目前在 Configuration.cs 的 Seed 方法中播种了一些参考数据。但在我看来,用户和角色表是在第一次遇到 AccountController 时才创建的。

我目前有两个连接字符串,因此我可以将我的身份验证数据分离到不同的数据库中。

如何让用户、角色等表与我的其他表一起填充?而不是在帐户控制器被击中时?

【问题讨论】:

标签: asp.net-mvc asp.net-mvc-5 entity-framework-migrations seeding


【解决方案1】:

以下是常用种子方法的示例:

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

我使用包管理器“更新数据库”。数据库和所有表都是用数据创建和播种的。

【讨论】:

  • 到 Configuration 类的 Seed 方法。配置是启用迁移的默认类名,但您可以更改它。
  • 你应该在包管理器控制台中使用'enable-migrations'。它将为您创建带有种子方​​法的配置类。
  • @Zapnologica Migrations 非常易于使用。它还允许您在不重新创建表格的情况下编辑表格。您只需熟悉使用 NuGet 包管理器控制台的三个命令。启用迁移、添加迁移和更新数据库。轻松豌豆。
  • 我在一个新的 mvc 5 Web 应用程序中将这段代码复制并粘贴到我的 Seed 方法中,然后在包管理器控制台中运行“update-database”。它添加了角色(我可以在 AspNetRoles 表中看到它),但是当涉及到 line manager.AddToRole(user.Id, "AppAdmin") 我收到错误消息“找不到用户 ID”。如果您知道我缺少什么,我将非常感谢您提供的信息。
  • 这个答案似乎不再适用于较新的版本,因为您不能再实例化 UserManager 和 RoleManager。
【解决方案2】:

这是一个很小的补充,但适用于“未找到用户 ID”的任何人。尝试播种时的消息:(Tom Regan 在 cmets 中有这个问题,我自己被卡了一段时间)

这意味着 manager.Create(user, "ChangeItAsap!") 没有成功。 这可能有不同的原因,但对我来说是因为我的密码没有通过验证。

我有一个自定义密码验证器,在为数据库播种时没有被调用,所以我习惯的验证规则(最小长度 4 而不是默认的 6)不适用。确保您的密码(以及与此相关的所有其他字段)正在通过验证。

【讨论】:

  • 这对我有帮助,因为我遇到了“找不到用户 ID”的问题。我设法用以下代码追踪它:IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
  • 那条评论太好了,它给了我“用户名演示用户无效,只能包含字母或数字。”而不是仅仅因为缺少 userId 而模棱两可地失败
  • 我发现我的密码验证规则也不起作用,知道吗?
【解决方案3】:

这是我基于 Valin 回答的方法,我在 db 中添加了角色并为用户添加了密码。这段代码放在 Migrations>Configurations.cs 中的Seed() 方法中。

// 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]);
    }

【讨论】:

    【解决方案4】:

    这里我有一个非常简单、干净和顺利的解决方案。

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

    【讨论】:

    • 很酷的事情,但你错过了一件重要的事情。您必须添加 user.SecurityStamp = Guid.NewGuid().ToString() 否则登录时会出错。
    • 谢谢。我没有使用该功能,但已将其添加到我的答案中。
    【解决方案5】:
    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);
      }
    }
    

    【讨论】:

    • 我将我的 ApplicationUser 自定义为具有 int 类型的 ID 属性。你的方法是我唯一可以使用我的自定义用户和角色存储的方法,谢谢!
    • 从概念的角度来看,这个位是完全不正确的:Task.Run(async () =&gt; { await SeedAsync(context); }).Wait();。你应该写SeedAsync(context).GetAwait().GetResult(); 稍微好一点。
    【解决方案6】:

    看起来他们改变了 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();
            }
        }
    }
    

    【讨论】:

    • 这个答案不再相关,因为 ASP.NET 身份 API 已更改。
    • @Josh McKearin 你有更好的解决方案吗?请分享
    【解决方案7】:

    在您的迁移配置中编写此代码。

    注意:在配置类中使用 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" }
                );
    
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-11-02
      • 2013-11-10
      • 2015-06-14
      • 2016-10-03
      • 2018-08-10
      • 2018-02-28
      • 1970-01-01
      • 2019-08-22
      • 2015-07-17
      相关资源
      最近更新 更多