Utenti e ruoli seed MVC 5


94

Sto giocando con il nuovo MVC 5, ho alcuni modelli, controller e impostazioni di viste utilizzando le migrazioni code first.

La mia domanda è: come si inseriscono utenti e ruoli? Attualmente semino alcuni dati di riferimento nel mio metodo Seed in Configuration.cs. Ma mi sembra che le tabelle degli utenti e dei ruoli non vengano create fino a quando qualcosa non colpisce prima AccountController.

Al momento ho due stringhe di connessione in modo da poter separare i miei dati dalla mia autenticazione in diversi database.

Come posso fare in modo che le tabelle utente, ruoli, ecc. Vengano popolate insieme alle mie altre? E non quando viene premuto il controller dell'account?


Risposte:


181

Ecco un esempio del solito approccio Seed:

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

Ho usato il gestore di pacchetti "update-database". DB e tutte le tabelle sono state create e seminate con i dati.


3
Al metodo Seed della classe Configurazione. La configurazione è il nome di classe predefinito per le migrazioni abilitate, ma è possibile modificarlo.
Valin

3
Dovresti usare "enable-migrations" nella console del gestore di pacchetti. Creerà una classe di configurazione con il metodo seed per te.
Valin

4
@Zapnologica Migrations è così facile da usare. Ti consente anche di modificare le tue tabelle senza ricrearle. Sono disponibili solo tre comandi per acquisire familiarità con l'utilizzo della console di Gestione pacchetti NuGet. Abilita migrazioni, aggiunta migrazione e aggiornamento database. Facile pacato.
yardpenalty.com

10
Ho letteralmente copiato e incollato questo codice nel mio metodo Seed in una nuova applicazione web mvc 5, quindi ho eseguito "update-database" nella console del gestore dei pacchetti. Aggiunge il ruolo (posso vederlo nella tabella AspNetRoles), ma quando si tratta di line manager.AddToRole (user.Id, "AppAdmin") ottengo il messaggio di errore "UserId non trovato". Se hai idea di cosa mi manchi, apprezzerei molto le informazioni.
Tom Regan

2
Mancato context.Users.Add(user);tra manager.Create(user, "ChangeItAsap!");e manager.AddToRole(user.Id, "AppAdmin");. Quindi l'utente neonato non ha User.Id.
ApceH Hypocrite

15

È una piccola aggiunta, ma per chiunque abbia "UserId non trovato". messaggio durante il tentativo di seed: (Tom Regan aveva questa domanda nei commenti e io stesso ci sono rimasto bloccato per un po ')

Ciò significa che manager.Create (utente, "ChangeItAsap!") Non ha avuto successo. Questo potrebbe avere un motivo diverso, ma per me era perché la mia password non riusciva a convalidare.

Avevo un validatore di password personalizzato, che non veniva chiamato durante il seeding del database, quindi le regole di convalida a cui ero abituato (lunghezza minima 4 anziché 6 predefinita) non si applicavano. Assicurati che la tua password (e tutti gli altri campi per quella materia) stia superando la convalida.


7
Questo mi ha aiutato perché avevo il problema "UserId non trovato". Sono riuscito a rintracciarlo con il seguente codice: IdentityResult result = manager.Create(user, "ChangeItAsap!"); if (result.Succeeded == false) { throw new Exception(result.Errors.First()); }
Steve Wilford il

Questo commento è eccellente, mi ha dato "Nome utente Demo Utente non valido, può contenere solo lettere o cifre". invece di fallire ambiguamente con un
ID utente

Ho scoperto che anche la mia regola di convalida della password non funziona, idea?
user1686407

15

Questo è il mio metodo basato sulla risposta di Valin, ho aggiunto ruoli in db e aggiunto la password per l'utente. Questo codice si trova nel Seed()metodo in 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

Qui ho una soluzione molto semplice, pulita e liscia.

 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
Bella cosa, ma ti sei perso una cosa importante. Devi aggiungere user.SecurityStamp = Guid.NewGuid (). ToString () o riceverai un errore al login.
Eddy White

Grazie. Non ho usato quella funzione ma l'ho aggiunta alla mia risposta.
Mr 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
Ho personalizzato il mio ApplicationUser per avere una proprietà ID di tipo int. Il tuo approccio è l'unico che ho potuto ottenere per lavorare con i miei User e RoleStores personalizzati, grazie!
Mike Devenney

1
Questo bit è completamente corretta da un punto di vista concettuale: Task.Run(async () => { await SeedAsync(context); }).Wait();. Dovresti piuttosto scrivere SeedAsync(context).GetAwait().GetResult();che è leggermente migliore.
Tanveer Badar

2

Sembra che cambino il modo in cui funziona l'autenticazione in MVC5, cambiato il mio Global.asax.cs nel seguente ha funzionato!

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
Questa risposta non è più pertinente poiché l'API di identità ASP.NET è cambiata.
Josh McKearin

@ Josh McKearin Hai una soluzione migliore? per favore condividi
Victor.Uduak

2

scrivi questo codice nella configurazione della migrazione.

nota: utilizzare ApplicationDbContext nella classe di configurazione.

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


    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.