using Features.Users.Identity; using Features.Users.Repository; using Features.Users.Services; using Infrastructure.PasswordHashing; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; namespace Features.Users.DependencyInjection; /// Registers the services required by Features.Users with the dependency injection container. public static class FeaturesUsersServiceCollectionExtensions { /// /// Adds , , /// , and ASP.NET Core Identity /// ( backed by and /// ) as scoped services. /// public static IServiceCollection AddFeaturesUsers(this IServiceCollection services) { services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); // AddDefaultTokenProviders() is deliberately not called: it registers // DataProtectorTokenProvider, which UserManager's constructor resolves eagerly and which // requires IDataProtectionProvider -- not registered in the plain-console-app DI containers this // solution builds (e.g. Database.Seed). Identity's own token providers are unused here anyway; // account confirmation keeps using its own JWT-based tokens (see ITokenService). services.AddIdentityCore(options => { options.User.RequireUniqueEmail = true; // Password/username complexity is already enforced by RegisterUserValidator // (FluentValidation); disable Identity's own checks to avoid duplicated/drifting rules. options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireUppercase = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequiredLength = 1; }); services.AddScoped(); services.AddScoped>(sp => sp.GetRequiredService() ); services.AddScoped>(sp => sp.GetRequiredService() ); services.AddScoped>(sp => sp.GetRequiredService() ); services.AddScoped, Argon2PasswordHasher>(); return services; } }