I have the following configurations in Startup.cs:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o => {
o.LoginPath = Routes.Urls.AdminAccountLogin;
o.AccessDeniedPath = Routes.Urls.AdminAccountAccessdenied;
}).AddJwtBearer(configureOptions => {});
The application throws the following exception when the controller Login action calls SignInManger.PasswordSignInAsync
:
Exception has occurred: CLR/System.InvalidOperationException
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll: 'No sign-in authentication handler is registered for the scheme 'Identity.Application'. The registered sign-in schemes are: Cookies. Did you forget to call AddAuthentication().AddCookies("Identity.Application",...)?'
Where does the Identity.Application
come from?
Authentication is the process of determining a user's identity. Authorization is the process of determining whether a user has access to a resource. In ASP.NET Core, authentication is handled by the authentication service, IAuthenticationService, which is used by authentication middleware.
SignInAsync(HttpContext, String, ClaimsPrincipal, AuthenticationProperties) Sign in a principal for the specified scheme.
The entire cookie-based authentication works in the following manner: The user gives a username and password at the time of login. Once the user fills in the login form, the browser (client) sends a login request to the server. The server verifies the user by querying the user data.
Short (and not as helpful) Answer:
Specifically it comes from the microsoft.aspnetcore.identity
package in the class Microsoft.AspNetCore.Identity.IdentityConstants.ApplicationScheme
Long Answer, with the whole breakdown:
You need to add Identity - That scheme is stood up and connected to authentication in the AddIdentity
extension method
The extension method is in Microsoft.Extensions.DependencyInjection.IdentityServiceCollectionExtensions
public static IdentityBuilder AddIdentity<TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupAction) where TUser: class where TRole: class
{
services.AddAuthentication(delegate (AuthenticationOptions options) {
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
}).AddCookie(IdentityConstants.ApplicationScheme, delegate (CookieAuthenticationOptions o) {
o.LoginPath = new PathString("/Account/Login");
CookieAuthenticationEvents events1 = new CookieAuthenticationEvents();
events1.OnValidatePrincipal = new Func<CookieValidatePrincipalContext, Task>(SecurityStampValidator.ValidatePrincipalAsync);
o.Events = events1;
}).AddCookie(IdentityConstants.ExternalScheme, delegate (CookieAuthenticationOptions o) {
o.Cookie.Name = IdentityConstants.ExternalScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes((double) 5.0);
}).AddCookie(IdentityConstants.TwoFactorRememberMeScheme, delegate (CookieAuthenticationOptions o) {
o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme;
CookieAuthenticationEvents events1 = new CookieAuthenticationEvents();
events1.OnValidatePrincipal = new Func<CookieValidatePrincipalContext, Task>(SecurityStampValidator.ValidateAsync<ITwoFactorSecurityStampValidator>);
o.Events = events1;
}).AddCookie(IdentityConstants.TwoFactorUserIdScheme, delegate (CookieAuthenticationOptions o) {
o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes((double) 5.0);
});
services.AddHttpContextAccessor();
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>>();
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>>();
if (setupAction != null)
{
services.Configure<IdentityOptions>(setupAction);
}
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}
If you follow this AddCookie
call
.AddCookie(IdentityConstants.ApplicationScheme, delegate (CookieAuthenticationOptions o) {
o.LoginPath = new PathString("/Account/Login");
CookieAuthenticationEvents events1 = new CookieAuthenticationEvents();
events1.OnValidatePrincipal = new Func<CookieValidatePrincipalContext, Task>(SecurityStampValidator.ValidatePrincipalAsync);
o.Events = events1;
it eventually configures AuthenticationOptions
with the "Identity.Application" scheme and a CookieAuthenticationHandler
When you call SignInManager.PasswordSignInAsync
:
SignInManager
checks the username/password in the database (and does two factor flow if enabled), then if goodClaimsPrincipal
and sends it to HttpContext.SignInAsync
(an extension method) with the identity application scheme, see here
IAuthenticationService
(added to DI by AddAuthentication
), see here
AuthenticationService
, it uses a chain of objects
IAuthenticationHandlerProvider
=> IAuthenticationSchemeProvider
=> the previously configured AuthenticationOptions
to construct an AuthenticationScheme
which serves up the IAuthenticationHandler
in this case CookieAuthenticationHandler
. see here and here and here
CookieAuthenticationHandler.HandleSignInAsync
creates, encrypts and adds the cookie. Now the cookie is there, so the next request (often a redirect after login) in the AuthenticationMiddleware
, the HttpContext.AuthenticateAsync
method is called, which follows a similar flow to
CookieAuthenticationHandler.HandleAuthenticateAsync
which reads the cookie and passes back a ClaimsPrincipal
,HttpContext.User
, making it accessible to all the other areas of the request pipeline, like authorization, see here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With