So erstellen Sie Rollen im asp.net-Kern und weisen sie Benutzern zu

75

Ich verwende die Standard-Website-Vorlage von asp.net core und die Authentifizierung, die als individuelles Benutzerkonto ausgewählt wurde. Wie kann ich eine Rolle erstellen und dem Benutzer zuweisen, damit ich die Rolle im Controller zum Filtern des Zugriffs verwenden kann?

Bipn Paul
quelle
Wissen Sie, wie Sie Benutzerrollen während der Anmeldung identifizieren können?
Yirga

Antworten:

62

Ich habe im Account Controller eine Aktion erstellt, die eine Funktion zum Erstellen der Rollen aufruft und die Administratorrolle für einen Standardbenutzer beeinflusst (Sie sollten wahrscheinlich den Standardbenutzer in der Produktion entfernen):

    private async Task createRolesandUsers()
    {  
        bool x = await _roleManager.RoleExistsAsync("Admin");
        if (!x)
        {
            // first we create Admin rool    
            var role = new IdentityRole();
            role.Name = "Admin";
            await _roleManager.CreateAsync(role);

            //Here we create a Admin super user who will maintain the website                   

            var user = new ApplicationUser();
            user.UserName = "default";
            user.Email = "[email protected]";

            string userPWD = "somepassword";

            IdentityResult chkUser = await _userManager.CreateAsync(user, userPWD);

            //Add default User to Role Admin    
            if (chkUser.Succeeded)
            {
                var result1 = await _userManager.AddToRoleAsync(user, "Admin");
            }
        }

        // creating Creating Manager role     
        x = await _roleManager.RoleExistsAsync("Manager");
        if (!x)
        {
            var role = new IdentityRole();
            role.Name = "Manager";
            await _roleManager.CreateAsync(role);
        }

        // creating Creating Employee role     
        x = await _roleManager.RoleExistsAsync("Employee");
        if (!x)
        {
            var role = new IdentityRole();
            role.Name = "Employee";
            await _roleManager.CreateAsync(role);
        }
  }

Nachdem Sie einen Controller zum Verwalten von Rollen für die Benutzer erstellen konnten.

Stephane Duteriez
quelle
Wie kann ich eine Liste aller Benutzer mit Rollen abrufen, Rollen widerrufen und zugehörige Rollen bearbeiten? Wie kann ich das tun?
Bipn Paul
1
@BipnPaul Dafür können Sie den Usermanager verwenden:_userManager.GetUsersInRoleAsync("admin");
Stephane Duteriez
Das ist großartig, aber wie können Sie diese Rollen Benutzern während der Registrierung zuweisen und die Benutzerrolle während der Anmeldung identifizieren? Bitte helfen Sie dabei stecken zu bleiben?
Yirga
1
Ich habe eine vollständige Jobprogrammierung mit js begonnen, also habe ich meinen Test mit asp.net auf old gestellt. Wenn Sie jedoch einen neuen Benutzer erstellen, sollten Sie "addToRoleAsync" mit dem neuen Benutzer aufrufen. Um das Recht des Benutzers zu kontrollieren, sollten Sie eine Methode verwenden, wie unten beschrieben [Authorize ("admin")].
Stephane Duteriez
4
Welcher Typ ist _roleManager?
JohnOsborne
91

Mein Kommentar wurde gelöscht, weil ich einen Link zu einer ähnlichen Frage bereitgestellt habe, die ich hier beantwortet habe . Ergo werde ich diesmal ausführlicher antworten. Hier geht.

Sie können dies einfach tun, indem Sie eine CreateRolesMethode in Ihrer startupKlasse erstellen . Auf diese Weise können Sie überprüfen, ob die Rollen erstellt wurden, und die Rollen erstellen, wenn dies nicht der Fall ist. beim Start der Anwendung. Wie so.

private async Task CreateRoles(IServiceProvider serviceProvider)
    {
        //initializing custom roles 
        var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
        var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
        string[] roleNames = { "Admin", "Manager", "Member" };
        IdentityResult roleResult;

        foreach (var roleName in roleNames)
        {
            var roleExist = await RoleManager.RoleExistsAsync(roleName);
            if (!roleExist)
            {
                //create the roles and seed them to the database: Question 1
                roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
            }
        }

        //Here you could create a super user who will maintain the web app
        var poweruser = new ApplicationUser
        {

            UserName = Configuration["AppSettings:UserName"],
            Email = Configuration["AppSettings:UserEmail"],
        };
    //Ensure you have these values in your appsettings.json file
        string userPWD = Configuration["AppSettings:UserPassword"];
        var _user = await UserManager.FindByEmailAsync(Configuration["AppSettings:AdminUserEmail"]);

       if(_user == null)
       {
            var createPowerUser = await UserManager.CreateAsync(poweruser, userPWD);
            if (createPowerUser.Succeeded)
            {
                //here we tie the new user to the role
                await UserManager.AddToRoleAsync(poweruser, "Admin");

            }
       }
    }

Anschließend können Sie die CreateRoles(serviceProvider).Wait();Methode über die ConfigureMethode in der Startup-Klasse aufrufen . Stellen Sie sicher, dass Sie IServiceProviderals Parameter in der ConfigureKlasse haben.

Verwenden der rollenbasierten Autorisierung in einem Controller zum Filtern des Benutzerzugriffs: Frage 2

Sie können dies einfach so tun.

[Authorize(Roles="Manager")]
public class ManageController : Controller
{
   //....
}

Sie können auch eine rollenbasierte Autorisierung in der Aktionsmethode verwenden. Weisen Sie mehrere Rollen zu, wenn Sie so wollen

[Authorize(Roles="Admin, Manager")]
public IActionResult Index()
{
/*
 .....
 */ 
}

Dies funktioniert zwar einwandfrei, aber für eine viel bessere Vorgehensweise sollten Sie sich über die Verwendung richtlinienbasierter Rollenprüfungen informieren. Sie finden es in der ASP.NET-Kerndokumentation hier oder in diesem Artikel, den ich hier geschrieben habe

Temi Lajumoke
quelle
2
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Aus dem Rückblick
Jean-François Fabre
3
Danke Jean. Ich habe die wesentlichen Teile des Codes in die Antwort aufgenommen und wie vorgeschlagen Links als Referenz bereitgestellt.
Temi Lajumoke
das fängt jetzt an gut auszusehen. +1 (weil Sie jetzt keine -1 verdienen)
Jean-François Fabre
1
Wäre es im neuen ApplicationUser-Teil besser, EmailConfirmed = true hinzuzufügen?
egmfrs
9
@ Mahmoudfathy Hinzufügen services.AddDefaultIdentity<ApplicationUser>().AddRoles<IdentityRole>().AddEntityFrameworkStores<DbContext>();zu IhremConfigureServices
Dennis de Laat
26

Temis Antwort ist fast richtig, aber Sie können eine asynchrone Funktion nicht von einer nicht asynchronen Funktion aus aufrufen, wie er vorschlägt. Was Sie tun müssen, ist asynchrone Aufrufe in einer synchronen Funktion wie folgt durchzuführen:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseIdentity();

        // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

        CreateRoles(serviceProvider);

    }

    private void CreateRoles(IServiceProvider serviceProvider)
    {

        var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
        var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
        Task<IdentityResult> roleResult;
        string email = "[email protected]";

        //Check that there is an Administrator role and create if not
        Task<bool> hasAdminRole = roleManager.RoleExistsAsync("Administrator");
        hasAdminRole.Wait();

        if (!hasAdminRole.Result)
        {
            roleResult = roleManager.CreateAsync(new IdentityRole("Administrator"));
            roleResult.Wait();
        }

        //Check if the admin user exists and create it if not
        //Add to the Administrator role

        Task<ApplicationUser> testUser = userManager.FindByEmailAsync(email);
        testUser.Wait();

        if (testUser.Result == null)
        {
            ApplicationUser administrator = new ApplicationUser();
            administrator.Email = email;
            administrator.UserName = email;

            Task<IdentityResult> newUser = userManager.CreateAsync(administrator, "_AStrongP@ssword!");
            newUser.Wait();

            if (newUser.Result.Succeeded)
            {
                Task<IdentityResult> newUserRole = userManager.AddToRoleAsync(administrator, "Administrator");
                newUserRole.Wait();
            }
        }

    }

Der Schlüssel dazu ist die Verwendung der Task <> -Klasse und das Erzwingen, dass das System synchron auf eine etwas andere Weise wartet.

Paul Mason
quelle
Ich denke nicht, dass Ihre Antwort für die Frage relevant ist.
The_Black_Smurf
Eigentlich denke ich, dass dies eine der besten Antworten ist, ABER ich würde diese UGLY Task <bool> nicht verwenden. HasAdminRole = roleManager.RoleExistsAsync ("Administrator"); und verwenden Sie stattdessen var adminRoleExist = roleManager.RoleExistsAsync ("Administrator"). Ergebnis; Ich mag auch nicht die Tatsache, dass eine E-Mail fest codiert ist, verschiebe den zweiten Teil auf den Register-Controller und wenn kein Administrator vorhanden ist, wird der Benutzer automatisch zur Administratorrolle hinzugefügt ...
L.Trabacchin
1
Warum nicht dies in das Programm einfügen, in dem der Main asynchron sein kann und wir die Rollenkonfiguration als IWebHost-Erweiterung verwenden? Dies scheint von einigen Microsofties vorgeschlagen zu werden (die Erweiterungen, nicht die Hauptasynchronisierung): docs.microsoft.com/en-us/archive/msdn-magazine/2019/april/…
Paulo Neves
8

Ich benutze dies (DI):

public class IdentitySeed
{
    private readonly ApplicationDbContext _context;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _rolesManager;
    private readonly ILogger _logger;

    public IdentitySeed(
        ApplicationDbContext context,
        UserManager<ApplicationUser> userManager,
        RoleManager<ApplicationRole> roleManager,
         ILoggerFactory loggerFactory) {
        _context = context;
        _userManager = userManager;
        _rolesManager = roleManager;
        _logger = loggerFactory.CreateLogger<IdentitySeed>();
    }

    public async Task CreateRoles() {
        if (await _context.Roles.AnyAsync()) {// not waste time
            _logger.LogInformation("Exists Roles.");
            return;
        }
        var adminRole = "Admin";
        var roleNames = new String[] { adminRole, "Manager", "Crew", "Guest", "Designer" };

        foreach (var roleName in roleNames) {
            var role = await _rolesManager.RoleExistsAsync(roleName);
            if (!role) {
                var result = await _rolesManager.CreateAsync(new ApplicationRole { Name = roleName });
                //
                _logger.LogInformation("Create {0}: {1}", roleName, result.Succeeded);
            }
        }
        // administrator
        var user = new ApplicationUser {
            UserName = "Administrator",
            Email = "[email protected]",
            EmailConfirmed = true
        };
        var i = await _userManager.FindByEmailAsync(user.Email);
        if (i == null) {
            var adminUser = await _userManager.CreateAsync(user, "Something*");
            if (adminUser.Succeeded) {
                await _userManager.AddToRoleAsync(user, adminRole);
                //
                _logger.LogInformation("Create {0}", user.UserName);
            }
        }
    }
    //! By: Luis Harvey Triana Vega
}
Harveyt
quelle
1
ApplicationRole wurde von IdentityRole installiert, da ich den Identitätsprimärschlüssel als GUID konfiguriere ( docs.microsoft.com/en-us/aspnet/core/security/authentication/… )
Harvey
Wie nennst du das?
Richard Barraclough
5

Der folgende Code funktioniert mit ISA.

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, 
        IServiceProvider serviceProvider)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseIdentity();

        // Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

        CreateRolesAndAdminUser(serviceProvider);
    }

    private static void CreateRolesAndAdminUser(IServiceProvider serviceProvider)
    {
        const string adminRoleName = "Administrator";
        string[] roleNames = { adminRoleName, "Manager", "Member" };

        foreach (string roleName in roleNames)
        {
            CreateRole(serviceProvider, roleName);
        }

        // Get these value from "appsettings.json" file.
        string adminUserEmail = "[email protected]";
        string adminPwd = "_AStrongP1@ssword!";
        AddUserToRole(serviceProvider, adminUserEmail, adminPwd, adminRoleName);
    }

    /// <summary>
    /// Create a role if not exists.
    /// </summary>
    /// <param name="serviceProvider">Service Provider</param>
    /// <param name="roleName">Role Name</param>
    private static void CreateRole(IServiceProvider serviceProvider, string roleName)
    {
        var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();

        Task<bool> roleExists = roleManager.RoleExistsAsync(roleName);
        roleExists.Wait();

        if (!roleExists.Result)
        {
            Task<IdentityResult> roleResult = roleManager.CreateAsync(new IdentityRole(roleName));
            roleResult.Wait();
        }
    }

    /// <summary>
    /// Add user to a role if the user exists, otherwise, create the user and adds him to the role.
    /// </summary>
    /// <param name="serviceProvider">Service Provider</param>
    /// <param name="userEmail">User Email</param>
    /// <param name="userPwd">User Password. Used to create the user if not exists.</param>
    /// <param name="roleName">Role Name</param>
    private static void AddUserToRole(IServiceProvider serviceProvider, string userEmail, 
        string userPwd, string roleName)
    {
        var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();

        Task<ApplicationUser> checkAppUser = userManager.FindByEmailAsync(userEmail);
        checkAppUser.Wait();

        ApplicationUser appUser = checkAppUser.Result;

        if (checkAppUser.Result == null)
        {
            ApplicationUser newAppUser = new ApplicationUser
            {
                Email = userEmail,
                UserName = userEmail
            };

            Task<IdentityResult> taskCreateAppUser = userManager.CreateAsync(newAppUser, userPwd);
            taskCreateAppUser.Wait();

            if (taskCreateAppUser.Result.Succeeded)
            {
                appUser = newAppUser;
            }
        }

        Task<IdentityResult> newUserRole = userManager.AddToRoleAsync(appUser, roleName);
        newUserRole.Wait();
    }
Mohammed Osman
quelle
3

Neben der Antwort von Temi Lajumoke ist zu beachten, dass nach dem Erstellen der erforderlichen Rollen und dem Zuweisen dieser Rollen zu bestimmten Benutzern in der ASP.NET Core 2.1 MVC-Webanwendung nach dem Starten der Anwendung möglicherweise ein Methodenfehler auftritt, z. B. das Registrieren oder Verwalten einer Konto:

InvalidOperationException: Dienst für Typ 'Microsoft.AspNetCore.Identity.UI.Services.IEmailSender' kann nicht aufgelöst werden, während versucht wird, 'WebApplication.Areas.Identity.Pages.Account.Manage.IndexModel' zu aktivieren.

Ein ähnlicher Fehler kann in der ConfigureServices-Methode durch Hinzufügen der AddDefaultUI () -Methode schnell behoben werden:

services.AddIdentity<IdentityUser, IdentityRole>()
//services.AddDefaultIdentity<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultUI()
    .AddDefaultTokenProviders();

Prüfen

 https://blogs.msdn.microsoft.com/webdev/2018/03/02/aspnetcore-2-1-identity-ui/

und verwandtes Thema auf Github:

 Weitere Informationen finden Sie unter https://github.com/aspnet/Docs/issues/6784 .

Und zum Zuweisen einer Rolle zu einem bestimmten Benutzer könnte die IdentityUser-Klasse anstelle von ApplicationUser verwendet werden.

Nikita Viul
quelle
2

Update im Jahr 2020. Hier ist ein anderer Weg, wenn Sie es vorziehen.

 IdentityResult res = new IdentityResult();
 var _role = new IdentityRole();
 _role.Name = role.RoleName;
  res = await _roleManager.CreateAsync(_role);
  if (!res.Succeeded)
  {
        foreach (IdentityError er in res.Errors)
        {
             ModelState.AddModelError(string.Empty, er.Description);
         }
         ViewBag.UserMessage = "Error Adding Role";
         return View();
  }
  else
  {
        ViewBag.UserMessage = "Role Added";
        return View();
   }
Dan
quelle