In ASP.NET Core, you can add various services for identification: AddDefaultIdentity
, AddIdentity
and AddIdentityCore
.
What's the difference between AddIdentity
and AddIdentityCore
?
In ASP.NET Core, you can add various services for identification: AddDefaultIdentity
, AddIdentity
and AddIdentityCore
.
What's the difference between AddIdentity
and AddIdentityCore
?
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:
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>>();
...
}
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.
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 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 © 2022 - 2024 — McMap. All rights reserved.