Người dùng và vai trò hạt giống MVC 5


94

Tôi đã chơi với MVC 5 mới, tôi có một vài mô hình, bộ điều khiển và thiết lập chế độ xem bằng cách sử dụng di chuyển đầu tiên mã.

Câu hỏi của tôi là làm cách nào để chuyển đổi người dùng và vai trò? Tôi hiện đang gieo một số dữ liệu tham chiếu trong phương pháp Seed của tôi trong Configuration.cs. Nhưng có vẻ như tôi thấy rằng bảng người dùng và vai trò không được tạo cho đến khi có thứ gì đó đầu tiên truy cập vào AccountController.

Tôi hiện có hai chuỗi kết nối để tôi có thể tách dữ liệu từ xác thực của mình thành các cơ sở dữ liệu khác nhau.

Làm cách nào để đưa bảng người dùng, vai trò, v.v. vào cùng với những người khác của tôi? Và không khi bộ điều khiển tài khoản bị đánh?


Câu trả lời:


181

Đây là ví dụ về cách tiếp cận Seed thông thường:

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

Tôi đã sử dụng package-manager "update-database". DB và tất cả các bảng đã được tạo và bắt đầu với dữ liệu.


3
Đến phương thức Seed của lớp Cấu hình. Cấu hình là tên lớp mặc định cho chuyển đổi kích hoạt, nhưng bạn có thể thay đổi nó.
Valin

3
Bạn nên sử dụng 'enable-migrations' trong bảng điều khiển trình quản lý gói. Nó sẽ tạo ra lớp cấu hình với phương thức hạt giống cho bạn.
Valin

4
@Zapnologica Migrations rất dễ sử dụng. Nó cũng cho phép bạn chỉnh sửa bảng của mình mà không cần tạo lại bảng. Chỉ có ba lệnh bạn cần tự làm quen với việc sử dụng Bảng điều khiển Trình quản lý Gói NuGet. Enable-Migrations, Add-Migration và update-database. Dễ dãi.
yardpenalty.com

10
Tôi thực sự đã sao chép và dán mã này vào phương thức Seed của mình trong một ứng dụng web mvc 5 mới và sau đó chạy "update-database" trong bảng điều khiển trình quản lý gói. Nó thêm vai trò (tôi có thể thấy nó trong bảng AspNetRoles), nhưng khi nói đến trình quản lý dòng.AddToRole (user.Id, "AppAdmin"), tôi nhận được thông báo lỗi "Không tìm thấy UserId." Nếu bạn có bất kỳ ý tưởng nào về những gì tôi đang thiếu, tôi sẽ đánh giá cao thông tin này.
Tom Regan

2
Bỏ lỡ context.Users.Add(user);giữa manager.Create(user, "ChangeItAsap!");manager.AddToRole(user.Id, "AppAdmin");. Vì vậy, người dùng sơ sinh không có User.Id.
ApceH Hypocrite

15

Đó là một bổ sung nhỏ, nhưng đối với bất kỳ ai có "UserId không tìm thấy." thông báo khi cố gắng gieo hạt: (Tom Regan có câu hỏi này trong phần nhận xét và bản thân tôi đã mắc kẹt với câu hỏi đó trong một thời gian)

Điều này có nghĩa là manager.Create (người dùng, "ChangeItAsap!") Không thành công. Điều này có thể có một lý do khác, nhưng đối với tôi là do mật khẩu của tôi không được xác thực thành công.

Tôi có một trình xác thực mật khẩu tùy chỉnh, không được gọi khi bắt đầu cơ sở dữ liệu, vì vậy các quy tắc xác thực mà tôi đã sử dụng (độ dài tối thiểu 4 thay vì độ dài mặc định 6) không áp dụng. Đảm bảo mật khẩu của bạn (và tất cả các trường khác cho vấn đề đó) đang được xác thực.


7
Điều này đã giúp tôi khi tôi gặp sự cố "Không tìm thấy UserId". Tôi đã quản lý để theo dõi nó với mã sau: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
Steve Wilford

Nhận xét đó rất tuyệt vời, nó cho tôi 'Tên người dùng Demo Người dùng không hợp lệ, chỉ có thể chứa chữ cái hoặc chữ số.' thay vì chỉ thất bại một cách mơ hồ với một userId bị thiếu
dougajmcdonald

Tôi thấy quy tắc xác thực mật khẩu của mình cũng không hoạt động, có ý kiến ​​gì không?
user1686407

15

Đây là phương pháp của tôi dựa trên câu trả lời Valin, tôi đã thêm vai trò trong db và thêm mật khẩu cho người dùng. Mã này được đặt trong Seed()phương thức trong 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

Ở đây tôi có một giải pháp rất dễ dàng, sạch sẽ và trơn tru.

 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
Điều tuyệt vời, nhưng bạn đã bỏ lỡ một điều quan trọng. Bạn phải thêm user.SecurityStamp = Guid.NewGuid (). ToString () nếu không bạn sẽ gặp lỗi khi đăng nhập.
màu trắng xoáy vào

Cám ơn. Tôi đã không sử dụng tính năng đó nhưng tôi đã thêm nó vào câu trả lời của mình.
Ông Tangjai

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
Tôi đã tùy chỉnh Người dùng ứng dụng của mình để có thuộc tính ID được nhập kiểu int. Cách tiếp cận của bạn là cách duy nhất tôi có thể làm việc với Người dùng tùy chỉnh và RoleStores của tôi, cảm ơn!
Mike Devenney

1
Bit này là hoàn toàn không chính xác từ một quan điểm về khái niệm của quan điểm: Task.Run(async () => { await SeedAsync(context); }).Wait();. Bạn nên viết SeedAsync(context).GetAwait().GetResult();cái nào tốt hơn một chút.
Tanveer Badar

2

Có vẻ như họ thay đổi cách xác thực hoạt động trong MVC5, đã thay đổi Global.asax.cs của tôi thành mẹo sau đây!

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
Câu trả lời này không còn phù hợp nữa vì API nhận dạng ASP.NET đã thay đổi.
Josh McKearin,

@Josh McKearin Bạn có giải pháp nào tốt hơn không? hãy chia sẻ
Victor.Uduak

2

viết mã này trong Cấu hình di chuyển của bạn.

lưu ý: Sử dụng ApplicationDbContext trong Lớp cấu hình.

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


    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.