ASP.NET Core身份验证:没有角色管理器服务

25

我有一个使用Identity的ASP.NET Core应用程序。它可以正常运行,但是当我尝试将自定义角色添加到数据库时遇到问题。

在启动时,我已将Identity和角色管理器添加为作用域服务,代码如下:

services.AddIdentity<Entities.DB.User, IdentityRole<int>>()
                .AddEntityFrameworkStores<MyDBContext, int>();

services.AddScoped<RoleManager<IdentityRole>>();

并且在启动时,我会在Configure中注入RoleManager并将其传递给我的自定义类RolesData

    public void Configure(
        IApplicationBuilder app, 
        IHostingEnvironment env, 
        ILoggerFactory loggerFactory,
        RoleManager<IdentityRole> roleManager
    )
    {

    app.UseIdentity();
    RolesData.SeedRoles(roleManager).Wait();
    app.UseMvc();

这是RolesData类:

public static class RolesData
{

    private static readonly string[] roles = new[] {
        "role1",
        "role2",
        "role3"
    };

    public static async Task SeedRoles(RoleManager<IdentityRole> roleManager)
    {

        foreach (var role in roles)
        {

            if (!await roleManager.RoleExistsAsync(role))
            {
                var create = await roleManager.CreateAsync(new IdentityRole(role));

                if (!create.Succeeded)
                {

                    throw new Exception("Failed to create role");

                }
            }

        }

    }

}

应用程序无错误构建,但在尝试访问时出现以下错误:

在激活“Microsoft.AspNetCore.Identity.RoleManager”时,无法解析类型为“Microsoft.AspNetCore.Identity.IRoleStore`1[Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole]”的服务。

我做错了什么?我的直觉告诉我在添加RoleManager作为服务时有问题。

附注:我在创建项目时使用了“No authentication”来从头开始学习Identity。


我建议创建另一个使用单独用户帐户的项目,这样您就可以将其与包括标识的模板设置进行比较。 - Joe Audette
一个全新的项目添加了“个人用户账户”,但没有包含任何设置角色的代码。 - Glenn Utter
不,它没有,但可能有一些代码可以连接您尚未正确连接的依赖项。 - Joe Audette
另外,您应该避免在“Configure”方法中注入作用域依赖项,例如RoleManager,因为这将阻止底层的DbContext被正确处理。相反,考虑使用IServiceScopeFactory.CreateScope()创建一个服务范围,在您的SeedRoles方法返回时将被处理(您可以参考https://github.com/openiddict/openiddict-samples/blob/master/samples/ClientCredentialsFlow/AuthorizationServer/Startup.cs#L98-L115进行查看示例)。 - Kévin Chalet
3个回答

31

我遇到了这个问题

没有类型为'Microsoft.AspNetCore.Identity.RoleManager`的服务

而这个页面是在谷歌上搜到的第一个结果。它没有回答我的问题,所以我想把我的解决方案放在这里,给其他可能遇到此问题的人作为参考。

ASP.NET Core 2.2

对我来说缺失的那一行是在Startup.cs文件中添加.AddRoles()

        services.AddDefaultIdentity<IdentityUser>()
            .AddRoles<IdentityRole>()
            .AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>();
希望这可以帮助到某个人
来源:https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.2(在底部)

那么UserManager呢? - Carlos Garcia
我正在为一家公司构建一个内部应用程序,因此我使用活动目录来授权用户并获取角色。 - Dave ت Maher

24

我做错了什么?我的直觉告诉我,我添加 RoleManager 服务的方式有问题。

注册部分实际上是正确的,但你应该移除services.AddScoped<RoleManager<IdentityRole>>(),因为通过services.AddIdentity()已经为你添加了角色管理器。

你的问题很可能是由于通用类型不匹配引起的:尽管你使用 IdentityRole<int> 调用 services.AddIdentity(),但却尝试使用 IdentityRole 来解析 RoleManager,而这等同于 IdentityRole<string>(在 ASP.NET Core Identity 中,string 是默认的键类型)。

更新你的 Configure 方法以接受一个 RoleManager<IdentityRole<int>> 参数就可以了。


1
这是一个很好的修复,非常有帮助。我还建议从DatabaseInitializer调用SeedRoles,以便从启动异步执行CreateUsers和角色,类似于code public async Task SeedAsync(){ await CreateUsersAsync(); await RolesData.SeedRoles(_roleManager);} - RussHooker
我有一个函数,其中我种子一些数据,包括角色。当我获取RoleManager服务时,我使用了serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();,但应该使用serviceProvider.GetRequiredService<RoleManager<IdentityRole<int>>>();来指定整数类型的泛型。 - Minasie Shibeshi

0

这是我的ASP.NET Core 2.2用户和角色解决方案种子

Startup.cs

services.AddDefaultIdentity<ApplicationUser>()
            .AddRoles<IdentityRole<Guid>>()
            .AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>();

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    ...
    ...
    SeedData.Initialize(app.ApplicationServices);
)

SeedData.cs

public static void Initialize(IServiceProvider serviceProvider)
{
    using (var scope = serviceProvider.CreateScope())
    {
        var provider = scope.ServiceProvider;
        var context = provider.GetRequiredService<ApplicationDbContext>();
        var userManager = provider.GetRequiredService<UserManager<ApplicationUser>>();
        var roleManager = provider.GetRequiredService<RoleManager<IdentityRole<Guid>>>();

        // automigration 
        context.Database.Migrate(); 
        InstallUsers(userManager, roleManager);
     }
 }

 private static void InstallUsers(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole<Guid>> roleManager)
    {
        const string USERNAME = "admin@mysite.com";
        const string PASSWORD = "123456ABCD";
        const string ROLENAME = "Admin";

        var roleExist = roleManager.RoleExistsAsync(ROLENAME).Result;
        if (!roleExist)
        {
            //create the roles and seed them to the database
            roleManager.CreateAsync(new IdentityRole<Guid>(ROLENAME)).GetAwaiter().GetResult();
        }

        var user = userManager.FindByNameAsync(USERNAME).Result;

        if (user == null)
        {
            var serviceUser = new ApplicationUser
            {
                UserName = USERNAME,
                Email = USERNAME
            };

            var createPowerUser = userManager.CreateAsync(serviceUser, PASSWORD).Result;
            if (createPowerUser.Succeeded)
            {
                var confirmationToken = userManager.GenerateEmailConfirmationTokenAsync(serviceUser).Result;
                var result = userManager.ConfirmEmailAsync(serviceUser, confirmationToken).Result;
                //here we tie the new user to the role
                userManager.AddToRoleAsync(serviceUser, ROLENAME).GetAwaiter().GetResult();
            }
        }
    }

这个方法对我产生了错误。我将 IdentityRole<Guid> 替换为 IdentityRole,然后它就像魔术般地运行了。 - Eric K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接