diff --git a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs index 313be4ae3f..bbba6e63ec 100644 --- a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs @@ -49,11 +49,25 @@ public class AbpSignInManager : SignInManager var user = await UserManager.FindByNameAsync(userName); if (user == null) { - user = await externalLoginProvider.CreateUserAsync(userName, externalLoginProviderInfo.Name); + if (externalLoginProvider is IExternalLoginProviderWithPassword externalLoginProviderWithPassword) + { + user = await externalLoginProviderWithPassword.CreateUserAsync(userName, externalLoginProviderInfo.Name, password); + } + else + { + user = await externalLoginProvider.CreateUserAsync(userName, externalLoginProviderInfo.Name); + } } else { - await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name); + if (externalLoginProvider is IExternalLoginProviderWithPassword externalLoginProviderWithPassword) + { + await externalLoginProviderWithPassword.UpdateUserAsync(user, externalLoginProviderInfo.Name, password); + } + else + { + await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name); + } } return await SignInOrTwoFactorAsync(user, isPersistent); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/ExternalLoginProviderBase.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/ExternalLoginProviderBase.cs index cfefad2a95..240bf208d8 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/ExternalLoginProviderBase.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/ExternalLoginProviderBase.cs @@ -16,7 +16,6 @@ public abstract class ExternalLoginProviderBase : IExternalLoginProvider protected IdentityUserManager UserManager { get; } protected IIdentityUserRepository IdentityUserRepository { get; } protected IOptions IdentityOptions { get; } - protected ExternalLoginProviderBase( IGuidGenerator guidGenerator, ICurrentTenant currentTenant, @@ -32,7 +31,7 @@ public abstract class ExternalLoginProviderBase : IExternalLoginProvider } public abstract Task TryAuthenticateAsync(string userName, string plainPassword); - + public abstract Task IsEnabledAsync(); public virtual async Task CreateUserAsync(string userName, string providerName) @@ -40,8 +39,14 @@ public abstract class ExternalLoginProviderBase : IExternalLoginProvider await IdentityOptions.SetAsync(); var externalUser = await GetUserInfoAsync(userName); - NormalizeExternalLoginUserInfo(externalUser, userName); + return await CreateUserAsync(externalUser, userName, providerName); + } + + protected virtual async Task CreateUserAsync(ExternalLoginUserInfo externalUser, string userName, string providerName) + { + NormalizeExternalLoginUserInfo(externalUser, userName); + var user = new IdentityUser( GuidGenerator.Create(), userName, @@ -81,8 +86,14 @@ public abstract class ExternalLoginProviderBase : IExternalLoginProvider public virtual async Task UpdateUserAsync(IdentityUser user, string providerName) { await IdentityOptions.SetAsync(); - + var externalUser = await GetUserInfoAsync(user); + + await UpdateUserAsync(user, externalUser, providerName); + } + + protected virtual async Task UpdateUserAsync(IdentityUser user, ExternalLoginUserInfo externalUser ,string providerName) + { NormalizeExternalLoginUserInfo(externalUser, user.UserName); if (!externalUser.Name.IsNullOrWhiteSpace()) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/ExternalLoginProviderWithPasswordBase.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/ExternalLoginProviderWithPasswordBase.cs new file mode 100644 index 0000000000..e791004fd0 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/ExternalLoginProviderWithPasswordBase.cs @@ -0,0 +1,70 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Identity; + +public abstract class ExternalLoginProviderWithPasswordBase : ExternalLoginProviderBase, IExternalLoginProviderWithPassword +{ + public bool CanObtainUserInfoWithoutPassword { get; } + + public ExternalLoginProviderWithPasswordBase( + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant, + IdentityUserManager userManager, + IIdentityUserRepository identityUserRepository, + IOptions identityOptions, + bool canObtainUserInfoWithoutPassword = false) : + base(guidGenerator, + currentTenant, + userManager, + identityUserRepository, + identityOptions) + { + CanObtainUserInfoWithoutPassword = canObtainUserInfoWithoutPassword; + } + + public async Task CreateUserAsync(string userName, string providerName, string plainPassword) + { + if (CanObtainUserInfoWithoutPassword) + { + return await CreateUserAsync(userName, providerName); + } + + await IdentityOptions.SetAsync(); + + var externalUser = await GetUserInfoAsync(userName, plainPassword); + + return await CreateUserAsync(externalUser, userName, providerName); + } + + public async Task UpdateUserAsync(IdentityUser user, string providerName, string plainPassword) + { + if (CanObtainUserInfoWithoutPassword) + { + await UpdateUserAsync(user, providerName); + return; + } + + await IdentityOptions.SetAsync(); + + var externalUser = await GetUserInfoAsync(user, plainPassword); + + await UpdateUserAsync(user, externalUser, providerName); + } + + protected override Task GetUserInfoAsync(string userName) + { + throw new NotImplementedException($"{nameof(GetUserInfoAsync)} is not implemented default. It should be overriden and implemented by the deriving class!"); + } + + protected abstract Task GetUserInfoAsync(string userName, string plainPassword); + + protected virtual Task GetUserInfoAsync(IdentityUser user, string plainPassword) + { + return GetUserInfoAsync(user.UserName, plainPassword); + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IExternalLoginProvider.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IExternalLoginProvider.cs index 52d3895d13..774c5a41db 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IExternalLoginProvider.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IExternalLoginProvider.cs @@ -28,10 +28,10 @@ public interface IExternalLoginProvider /// The name of this provider /// The user that can be updated Task UpdateUserAsync(IdentityUser user, string providerName); - + /// /// Return a value indicating whether this source is enabled. /// /// Task IsEnabledAsync(); -} +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IExternalLoginProviderWithPassword.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IExternalLoginProviderWithPassword.cs new file mode 100644 index 0000000000..fa811c852e --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IExternalLoginProviderWithPassword.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Identity +{ + public interface IExternalLoginProviderWithPassword + { + bool CanObtainUserInfoWithoutPassword { get; } + + /// + /// This method is called when a user is authenticated by this source but the user does not exists yet. + /// So, the source should create the user and fill the properties. + /// + /// User name + /// The name of this provider + /// The plain password of the user + /// Newly created user + Task CreateUserAsync(string userName, string providerName, string plainPassword); + + /// + /// This method is called after an existing user is authenticated by this source. + /// It can be used to update some properties of the user by the source. + /// + /// The name of this provider + /// The user that can be updated + /// The plain password of the user + Task UpdateUserAsync(IdentityUser user, string providerName, string plainPassword); + } +} \ No newline at end of file