How to Customize the SignIn Manager for ABP Applications
After creating a new application using the application startup template, you may want extend or change the default behavior of the SignIn Manager for your authentication and registration flow needs. ABP Account Module uses the Identity Management Module for SignIn Manager and the Identity Management Module uses default Microsoft Identity SignIn Manager (see here).
To write your Custom SignIn Manager, you need to extend Microsoft Identity SignIn Manager class and register it to the DI container.
This document explains how to customize the SignIn Manager for your own application.
Create a CustomSignInManager
Create a new class inheriting the SignInMager of Microsoft Identity package.
public class CustomSignInManager : Microsoft.AspNetCore.Identity.SignInManager<Volo.Abp.Identity.IdentityUser>
{
public CustomSignInManager(
Microsoft.AspNetCore.Identity.UserManager<Volo.Abp.Identity.IdentityUser> userManager,
Microsoft.AspNetCore.Http.IHttpContextAccessor contextAccessor,
Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<Volo.Abp.Identity.IdentityUser> claimsFactory,
Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Identity.IdentityOptions> optionsAccessor,
Microsoft.Extensions.Logging.ILogger<Microsoft.AspNetCore.Identity.SignInManager<Volo.Abp.Identity.IdentityUser>> logger,
Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemes,
Microsoft.AspNetCore.Identity.IUserConfirmation<Volo.Abp.Identity.IdentityUser> confirmation)
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
{
}
}
It is important to use Volo.Abp.Identity.IdentityUser type for SignInManager to inherit, not the AppUser of your application.
Afterwards you can override any of the SignIn Manager methods you need and add new methods and properties needed for your authentication or registration flow.
Overriding the GetExternalLoginInfoAsync Method
In this case we'll be overriding the GetExternalLoginInfoAsync
method which is invoked when a third party authentication is implemented.
A good way to override a method is copying its source code. In this case, we will be using a minorly modified version of the source code which explicitly shows the namespaces of the methods and properties to help better understanding of the concept.
public override async Task<Microsoft.AspNetCore.Identity.ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null)
{
var auth = await Context.AuthenticateAsync(Microsoft.AspNetCore.Identity.IdentityConstants.ExternalScheme);
var items = auth?.Properties?.Items;
if (auth?.Principal == null || items == null || !items.ContainsKey("LoginProviderKey"))
{
return null;
}
if (expectedXsrf != null)
{
if (!items.ContainsKey("XsrfKey"))
{
return null;
}
var userId = items[XsrfKey] as string;
if (userId != expectedXsrf)
{
return null;
}
}
var providerKey = auth.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var provider = items[LoginProviderKey] as string;
if (providerKey == null || provider == null)
{
return null;
}
var providerDisplayName = (await GetExternalAuthenticationSchemesAsync()).FirstOrDefault(p => p.Name == provider)?.DisplayName
?? provider;
return new Microsoft.AspNetCore.Identity.ExternalLoginInfo(auth.Principal, provider, providerKey, providerDisplayName)
{
AuthenticationTokens = auth.Properties.GetTokens()
};
}
To get your overridden method invoked and your customized SignIn Manager class to work, you need to register your class to the Dependency Injection System.
Register to Dependency Injection
Registering CustomSignInManager
should be done with adding AddSignInManager extension method of the IdentityBuilderExtensions of the IdentityBuilder.
Inside your .Web
project, locate the YourProjectNameWebModule
and add the following code under the PreConfigureServices
method to replace the old SignInManager
with your customized one:
PreConfigure<IdentityBuilder>(identityBuilder =>
{
identityBuilder.AddSignInManager<CustomSignInManager>();
});
The Source Code
You can find the source code of the completed example here.