AddIdentity vs AddIdentityCore
Asked Answered
P

2

99

In ASP.NET Core, you can add various services for identification: AddDefaultIdentity, AddIdentity and AddIdentityCore.

What's the difference between AddIdentity and AddIdentityCore?

Pylle answered 26/3, 2019 at 16:5 Comment(0)
L
135

AddIdentityCore adds the services that are necessary for user-management actions, such as creating users, hashing passwords, etc. Here's the relevant source:

public static IdentityBuilder AddIdentityCore<TUser>(this IServiceCollection services, Action<IdentityOptions> setupAction)
    where TUser : class
{
    // Services identity depends on
    services.AddOptions().AddLogging();

    // Services used by identity
    services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
    services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
    services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
    services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
    
    // No interface for the error describer so we can add errors without rev'ing the interface
    services.TryAddScoped<IdentityErrorDescriber>();
    services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
    services.TryAddScoped<UserManager<TUser>>();

    ...
}

Essentially, this boils down to registering an instance of UserManager<TUser>, but first registers all of its dependencies. With these services registered, you can retrieve an instance of UserManager<TUser> from DI and create users, set passwords, change emails, etc.

AddIdentity registers the same services as AddIdentityCore, with a few extras:

  • Cookie-based authentication schemes for the application itself, external sign-in (e.g. Facebook and Google), and 2FA.
  • The SignInManager, which effectively sits on top of the UserManager as a sort of orchestrator. For example, PasswordSignInAsync uses UserManager to retrieve a user, verify the password (if set) and then takes care of cookie creation.
  • AddIdentity itself also takes a TRole and registers the services that are necessary for supporting Roles.

Here's the AddIdentity source for completeness:

public static IdentityBuilder AddIdentity<TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupAction)
    where TUser : class
    where TRole : class
{
    // Services used by identity
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    .AddCookie(IdentityConstants.ApplicationScheme, o =>
    {
        o.LoginPath = new PathString("/Account/Login");
        o.Events = new CookieAuthenticationEvents
        {
            OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
        };
    })
    .AddCookie(IdentityConstants.ExternalScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.ExternalScheme;
        o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    })
    .AddCookie(IdentityConstants.TwoFactorRememberMeScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme;
        o.Events = new CookieAuthenticationEvents
        {
            OnValidatePrincipal = SecurityStampValidator.ValidateAsync<ITwoFactorSecurityStampValidator>
        };
    })
    .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
        o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    });

    // Hosting doesn't add IHttpContextAccessor by default
    services.AddHttpContextAccessor();
    
    // Identity services
    services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
    services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
    services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
    services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
    services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
    // No interface for the error describer so we can add errors without rev'ing the interface
    services.TryAddScoped<IdentityErrorDescriber>();
    services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
    services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
    services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
    services.TryAddScoped<UserManager<TUser>>();
    services.TryAddScoped<SignInManager<TUser>>();
    services.TryAddScoped<RoleManager<TRole>>();

    ...
}
Linseed answered 26/3, 2019 at 16:27 Comment(3)
Is the core module faster?Insistency
It's not about performance. Either one uses the same core with same performance. However, if you load more features, it will take slightly longer to initialize and take slightly more memory.Pylle
@Insistency the "Core" keyword of "AddIdentityCore" does not indicate it being more up-to-date than "AddIdentity". It only means that it comes with the core functionality, literally.Endocarp
E
26

AddIdentityCore is the most minimal way of adding authentication and authorization services to your application. It provides a minimal set of options and is intended for advanced scenarios where you want to have a clean starting point to configure Authentication and Authorization further yourself (assuming you will need further modifications to add more services, etc). It does NOT add some services such as Cookie Schemes, SignInManager, or RoleManager.

Note that the "Core" keyword in this method does not indicate it being more up-to-date than AddIdentity. It only means that it comes with the core functionality of Identity, literally. (confusing, I know..)

AddIdentity adds everything AddIdentityCore adds, with some extra services, namely Cookie Schemes (Application, External, and 2FA Schemes are all registered), SignInManager, and RoleManager. Note that AddIdentity adds Role services automatically, unlike AddDefaultIdentity.

AddDefaultIdentity is (arguably) the most convenient way for adding authentication and authorization services to your application, because it comes with a lot of pre-configured options that are suitable for most applications, and it also calls "AddDefaultUI" to add the default UI components under the "Identity" area. It is suitable for scenarios where you want to get up and running quickly with a reasonable set of defaults and a working UI.

Note that AddDefaultIdentity does NOT add Role services, so if you want to use AddDefaultIdentity and also want to have Role services to your application (which you most likely do), you must call "AddRoles" explicitly with it, like so;

services.AddDefaultIdentity<IdentityUser>(options => { 
    // options are set here
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();

Important Note: AddRoles must be added BEFORE AddEntityFrameworkStores, otherwise you will get vague errors and it will be difficult to figure out the cause of the issue.

Endocarp answered 1/2, 2023 at 8:21 Comment(4)
Brilliant! But I couldn't get it work in my ASP.NET 8 MVC project. I get a System.InvalidOperationException. Message=Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddRazorPages' inside the call to 'ConfigureServices(...)' in the application startup code.Stanstance
@SinanILYAS the "default UI" in Identity is a set of Razor pages, so you need to call AddRazorPages to enable Razor page routing - otherwise the routing middleware won't be able to map requests to those razor pages. You can have Razor pages routing and MVC routing in a project at the same time.Endocarp
Im fiddling with this a bit, and when using AddDefaultIdentity with JWT tokens I get an Unauthorized 401, but when using AddIdentity because I dont need the defaultUI, i get a 404. How can one use AddIdentity with getting the 401?Modiste
@Modiste try adding "AddDefaultTokenProviders()", something like: services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();Endocarp

© 2022 - 2024 — McMap. All rights reserved.