MVC 5种子用户和角色


94

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

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

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

如何获取用户,角色等表格以及其他表格?而不是当帐户控制器被击中时?


Answers:


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

我使用了包管理器“更新数据库”。数据库和所有表均已创建并填充了数据。


3
到Configuration类的Seed方法。配置是enable-migrations的默认类名,但是您可以更改它。
Valin 2014年

3
您应该在程序包管理器控制台中使用“ enable-migrations”。它将为您创建带有种子方​​法的配置类。
Valin

4
@Zapnologica迁移是如此易于使用。它还允许您编辑表而无需重新创建表。您仅需三个命令即可熟悉使用NuGet软件包管理器控制台的过程。启用迁移,添加迁移和更新数据库。容易豆豆。
yardpenalty.com 2014年

10
我从字面上复制了此代码并将其粘贴到新的mvc 5 Web应用程序的Seed方法中,然后在程序包管理器控制台中运行了“ update-database”。它添加了角色(我可以在AspNetRoles表中看到它),但是当涉及到线路管理器时。AddToRole(user.Id,“ AppAdmin”)我收到错误消息“找不到UserId”。如果您有任何想法,我将不胜感激。
汤姆·里根

2
context.Users.Add(user);之间错过了。因此,新生用户没有User.Id。manager.Create(user, "ChangeItAsap!");manager.AddToRole(user.Id, "AppAdmin");
ApceH Hypocrite

15

这是一个很小的补充,但是对于拥有“未找到UserId”的任何人。尝试播种时出现的消息:(汤姆·雷根(Tom Regan)在评论中有这个问题,我自己停留了一段时间)

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

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


7
当我遇到“找不到UserId”问题时,这对我有所帮助。我设法通过以下代码进行跟踪: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
Steve Wilford 2015年

该评论很好,它给了我“用户名演示用户无效,只能包含字母或数字”。而不只是一个丢失了用户id含糊失败
dougajmcdonald

我发现我的密码验证规则也行不通,知道吗?
user1686407 '16

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(),否则登录时将出现错误。
涡流白

谢谢。我没有使用该功能,但已将其添加到我的答案中。
唐杰先生17年

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属性。您的方法是我可以使用自定义用户和RoleStore的唯一方法,谢谢!
Mike Devenney '17

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您有更好的解决方案吗?请分享
Victor.Uduak

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


    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.