// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Identity.Core; namespace Microsoft.AspNetCore.Identity { /// /// Helper functions for configuring identity services. /// public class IdentityBuilder { /// /// Creates a new instance of . /// /// The to use for the users. /// The to attach to. public IdentityBuilder(Type user, IServiceCollection services) { UserType = user; Services = services; } /// /// Creates a new instance of . /// /// The to use for the users. /// The to use for the roles. /// The to attach to. public IdentityBuilder(Type user, Type role, IServiceCollection services) : this(user, services) => RoleType = role; /// /// Gets the used for users. /// /// /// The used for users. /// public Type UserType { get; private set; } /// /// Gets the used for roles. /// /// /// The used for roles. /// public Type RoleType { get; private set; } /// /// Gets the services are attached to. /// /// /// The services are attached to. /// public IServiceCollection Services { get; private set; } private IdentityBuilder AddScoped(Type serviceType, Type concreteType) { Services.AddScoped(serviceType, concreteType); return this; } /// /// Adds an for the . /// /// The user validator type. /// The current instance. public virtual IdentityBuilder AddUserValidator() where TValidator : class => AddScoped(typeof(IUserValidator<>).MakeGenericType(UserType), typeof(TValidator)); /// /// Adds an for the . /// /// The type of the claims principal factory. /// The current instance. public virtual IdentityBuilder AddClaimsPrincipalFactory() where TFactory : class => AddScoped(typeof(IUserClaimsPrincipalFactory<>).MakeGenericType(UserType), typeof(TFactory)); /// /// Adds an . /// /// The type of the error describer. /// The current instance. public virtual IdentityBuilder AddErrorDescriber() where TDescriber : IdentityErrorDescriber { Services.AddScoped(); return this; } /// /// Adds an for the . /// /// The validator type used to validate passwords. /// The current instance. public virtual IdentityBuilder AddPasswordValidator() where TValidator : class => AddScoped(typeof(IPasswordValidator<>).MakeGenericType(UserType), typeof(TValidator)); /// /// Adds an for the . /// /// The user store type. /// The current instance. public virtual IdentityBuilder AddUserStore() where TStore : class => AddScoped(typeof(IUserStore<>).MakeGenericType(UserType), typeof(TStore)); /// /// Adds a token provider. /// /// The type of the token provider to add. /// The name of the provider to add. /// The current instance. public virtual IdentityBuilder AddTokenProvider(string providerName) where TProvider : class => AddTokenProvider(providerName, typeof(TProvider)); /// /// Adds a token provider for the . /// /// The name of the provider to add. /// The type of the to add. /// The current instance. public virtual IdentityBuilder AddTokenProvider(string providerName, Type provider) { if (!typeof(IUserTwoFactorTokenProvider<>).MakeGenericType(UserType).GetTypeInfo().IsAssignableFrom(provider.GetTypeInfo())) { throw new InvalidOperationException(Resources.FormatInvalidManagerType(provider.Name, "IUserTwoFactorTokenProvider", UserType.Name)); } Services.Configure(options => { options.Tokens.ProviderMap[providerName] = new TokenProviderDescriptor(provider); }); Services.AddTransient(provider); return this; } /// /// Adds a for the . /// /// The type of the user manager to add. /// The current instance. public virtual IdentityBuilder AddUserManager() where TUserManager : class { var userManagerType = typeof(UserManager<>).MakeGenericType(UserType); var customType = typeof(TUserManager); if (!userManagerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo())) { throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "UserManager", UserType.Name)); } if (userManagerType != customType) { Services.AddScoped(customType, services => services.GetRequiredService(userManagerType)); } return AddScoped(userManagerType, customType); } /// /// Adds Role related services for TRole, including IRoleStore, IRoleValidator, and RoleManager. /// /// The role type. /// The current instance. public virtual IdentityBuilder AddRoles() where TRole : class { RoleType = typeof(TRole); AddRoleValidator>(); Services.TryAddScoped>(); Services.AddScoped(typeof(IUserClaimsPrincipalFactory<>).MakeGenericType(UserType), typeof(UserClaimsPrincipalFactory<,>).MakeGenericType(UserType, RoleType)); return this; } /// /// Adds an for the . /// /// The role validator type. /// The current instance. public virtual IdentityBuilder AddRoleValidator() where TRole : class { if (RoleType == null) { throw new InvalidOperationException(Resources.NoRoleType); } return AddScoped(typeof(IRoleValidator<>).MakeGenericType(RoleType), typeof(TRole)); } /// /// Adds an and . /// /// The personal data protector type. /// The personal data protector key ring type. /// The current instance. public virtual IdentityBuilder AddPersonalDataProtection() where TProtector : class,ILookupProtector where TKeyRing : class, ILookupProtectorKeyRing { Services.AddSingleton(); Services.AddSingleton(); Services.AddSingleton(); return this; } /// /// Adds a for the . /// /// The role store. /// The current instance. public virtual IdentityBuilder AddRoleStore() where TStore : class { if (RoleType == null) { throw new InvalidOperationException(Resources.NoRoleType); } return AddScoped(typeof(IRoleStore<>).MakeGenericType(RoleType), typeof(TStore)); } /// /// Adds a for the . /// /// The type of the role manager to add. /// The current instance. public virtual IdentityBuilder AddRoleManager() where TRoleManager : class { if (RoleType == null) { throw new InvalidOperationException(Resources.NoRoleType); } var managerType = typeof(RoleManager<>).MakeGenericType(RoleType); var customType = typeof(TRoleManager); if (!managerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo())) { throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "RoleManager", RoleType.Name)); } if (managerType != customType) { Services.AddScoped(typeof(TRoleManager), services => services.GetRequiredService(managerType)); } return AddScoped(managerType, typeof(TRoleManager)); } } }