我正在 ASP.NET Web API 应用程序中试验新的身份基础架构(按照 https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view =aspnetcore-8.0).
在启动时,一旦构建了
WebApplication
并在运行它之前,我想获取UserManager<AppUser>
的实例(其中AppUser
只是从IdentityUser
派生的类)和RoleManager<IdentityRole>
,以便我可以播种一些预设的用户帐户。
AFAIK,在启动时播种数据的正确方法是为
IHost
创建一个扩展方法,并在运行应用程序之前在我的 Program.cs
Main
函数中调用它,例如:
public static async Task<IHost> SeedAsync(this IHost host)
{
using var scope = host.Services.CreateScope();
IServiceProvider serviceProvider = scope.ServiceProvider;
// ... use services like UserManager and RoleManager to seed user accounts ...
}
无论如何,似乎虽然
UserManager
已按预期注册,但RoleManager
没有可用的服务:当尝试获取它时,我收到异常“'No service for type 'Microsoft.AspNetCore.Identity.RoleManager`1 [Microsoft.AspNetCore.Identity.IdentityRole]'已注册。'"。
这是一个示例重现过程:
(1) 创建一个新的 ASP.NET Core 8 Web API 应用程序。未选择身份。
(2)添加包:
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore.InMemory
(3)添加
AppUser.cs
和AppDbContext.cs
,并将Program.cs
更改如下:
// AppUser.cs
public class AppUser : IdentityUser
{
}
// AppDbContext.cs
public class AppDbContext : IdentityDbContext<AppUser>
{
public AppDbContext(DbContextOptions<AppDbContext> options) :
base(options)
{ }
}
// Program.cs
public static class Program
{
private static void ConfigureAuthServices(IServiceCollection services,
IConfiguration configuration)
{
services.AddDbContext<AppDbContext>(
options => options.UseInMemoryDatabase("Test"));
services.AddAuthorization();
services.AddIdentityApiEndpoints<AppUser>()
.AddEntityFrameworkStores<AppDbContext>();
}
private static void ConfigureServices(IServiceCollection services,
IConfiguration configuration)
{
// auth
ConfigureAuthServices(services, configuration);
// API controllers
services.AddControllers();
// Swagger/OpenAPI (https://aka.ms/aspnetcore/swashbuckle)
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
// database initializer
services.AddScoped(sp =>
{
return new AppDatabaseInitializer(
sp.GetRequiredService<UserManager<AppUser>>(),
sp.GetRequiredService<RoleManager<IdentityRole>>(),
configuration,
sp.GetRequiredService<ILogger<AppDatabaseInitializer>>());
});
}
public static async Task Main(string[] args)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
ConfigureServices(builder.Services, builder.Configuration);
WebApplication app = builder.Build();
app.MapGroup("/account").MapIdentityApi<AppUser>();
app.UseSwagger();
app.UseSwaggerUI();
app.UseAuthorization();
app.MapControllers();
// testing DI for services
using (var scope = app.Services.CreateScope())
{
// this works
var um = scope.ServiceProvider.GetRequiredService<UserManager<AppUser>>();
// ==> THIS THROWS
var rm = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
}
// here I would call await app.SeedAsync(); using my extension method
// for IHost, using an AppDatabaseInitializer service requiring UserManager
// and RoleManager via DI. Yet, it would fail just like the above code.
app.Run();
}
}
如果你现在运行,你会看到它在尝试获取
RoleManager
时抛出异常(虽然它成功获取 UserManager
)。我应该如何配置这个 V8 Identity
系统,以便为 DI 正确配置 RoleManager
?
在
.AddRoles<IdentityRole>()
之前添加 .AddEntityFrameworkStores<AppDbContext>
,如下所示:
services.AddIdentityApiEndpoints<AppUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>();
现在您将能够在构造函数中成功注入
RoleManager<IdentityRole> roleManager
。