【问题标题】:ASP.NET Core Identity Add custom user roles on application startupASP.NET Core Identity 在应用程序启动时添加自定义用户角色
【发布时间】:2017-02-17 10:53:53
【问题描述】:

在 ASP.NET Core 应用程序中,我想创建某些角色作为管理不同用户权限的基础。可悲的是,文档详细说明了如何使用自定义角色,例如在控制器/动作中,但不是如何创建它们。我发现我可以为此使用RoleManager<IdentityRole>,当在应用程序中注册其定义的和 ASP.NET Core 身份时,实例会自动注入到控制器构造函数中。

这让我可以像这样添加一个自定义角色:

var testRole = new IdentityRole("TestRole");
if(!roleManager.RoleExistsAsync(testRole.Name).Result) {
    roleManager.CreateAsync(testRole);
}

它工作并在数据库中创建角色。但是这个检查总是会在数据库上产生开销,调用特定的控制器/动作。所以我想在我的应用程序启动后检查一次,如果自定义角色存在并添加它们。 Startup.cs 中的ConfigureServices 方法似乎对此很有用。

但是:我如何创建RoleManager<IdentityRole> 类的实例来执行此操作?我想在这里使用最佳实践方法,而不是通过自己创建依赖实例来搞乱,这似乎会导致很多工作,因为它没有很好的文档记录并且肯定不会遵循最佳实践,因为 ASP.NET Core 正在使用像这样的事情的依赖注入(这在我看来也是合理的)。

换句话说:我需要在控制器的外部使用依赖注入。

【问题讨论】:

标签: c# asp.net-core asp.net-core-mvc user-roles


【解决方案1】:

以防万一有人来这里寻找 .NET 5 解决方案,这里是:

一切都与@Millan Sanchez 的答案几乎相同,除了 Configure 方法中的一点......

我得到了

One or more errors occurred. (Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.RoleManager`1[Microsoft.AspNetCore.Identity.IdemtityRole]' from root provider.)' 

经过一番搜索,我发现了这个StackOverflow answer

基本上,我需要做的只是将 IServiceProvider 添加到 Configure 方法的参数中,并将其传递给我对 SeedUsers 的调用,而不是 app.applicationServices

完整代码:

public static class RolesData
{
    private static readonly string[] Roles = new string[] { "Administrator", "Editor", "Subscriber" };

    public static async Task SeedRoles(IServiceProvider serviceProvider)
    {
        using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            var dbContext = serviceScope.ServiceProvider.GetService<AppDbContext>();

            if (!dbContext.UserRoles.Any())
            {
                var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();

                foreach (var role in Roles)
                {
                    if (!await roleManager.RoleExistsAsync(role))
                    {
                        await roleManager.CreateAsync(new IdentityRole(role));
                    }
                }
            }

        }
    }
}

在 Startup.cs 上:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
IServiceProvider serviceProvider)
{
    ...

    RolesData.SeedRoles(serviceProvider).Wait();
}

【讨论】:

    【解决方案2】:

    以下是满足您在启动时迁移和植入数据库的需求的示例:

    创建一个静态类:

    public static class RolesData
    {
        private static readonly string[] Roles = new string[] {"Administrator", "Editor", "Subscriber"};
    
        public static async Task SeedRoles(IServiceProvider serviceProvider)
        {
            using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                var dbContext = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
    
                if (dbContext.Database.GetPendingMigrations().Any())
                {
                    await dbContext.Database.MigrateAsync();
    
                    var roleManager = serviceScope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
    
                    foreach (var role in Roles)
                    {
                        if (!await roleManager.RoleExistsAsync(role))
                        {
                            await roleManager.CreateAsync(new IdentityRole(role));
                        }
                    }
                }
            }
        }
    }
    

    Startup.cs:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ...
    
        RolesData.SeedRoles(app.ApplicationServices).Wait();
    }
    

    【讨论】:

    • 如果您使用迁移,if (await db.Database.EnsureCreatedAsync()) 条件为false,因此不会创建任何角色。
    • @Artholl 不错。我替换为if (dbContext.Database.GetPendingMigrations().Any())await dbContext.Database.MigrateAsync();
    • 当我使用dbContext.Database.GetPendingMigrations().Any() 时,我得到了'DatabaseFacade' does not contain a definition for 'GetPendingMigrations'
    • @tmg,代码没有引起问题,但也没有做它应该做的事情。为什么要将种子角色的创建与待处理的迁移检查联系起来?为什么不只是选择角色并查看它是否存在,如果不存在,则添加它。
    • @HenriqueDuarte 代码试图从错误的范围解析RoleManager 的实例。我更新了答案来解决这个问题。
    【解决方案3】:

    我宁愿只在数据库中没有插入任何角色的情况下才为数据播种。换句话说,只有在应用程序第一次运行时才存储角色:

    public static class RolesData
    {
        private static readonly string[] Roles = new string[] { "Administrator", "Editor", "Subscriber" };
    
        public static async Task SeedRoles(IServiceProvider serviceProvider)
        {
            using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                var dbContext = serviceScope.ServiceProvider.GetService<AppDbContext>();
    
                if (!dbContext.UserRoles.Any())
                {
                    var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
    
                    foreach (var role in Roles)
                    {
                        if (!await roleManager.RoleExistsAsync(role))
                        {
                            await roleManager.CreateAsync(new IdentityRole(role));
                        }
                    }
                }
    
            }
        }
    }
    

    在 Startup.cs 上:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ...
    
        RolesData.SeedRoles(app.ApplicationServices).Wait();
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-21
      • 2022-11-23
      • 1970-01-01
      • 1970-01-01
      • 2014-08-08
      • 2022-10-24
      • 2020-12-06
      • 1970-01-01
      相关资源
      最近更新 更多