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 6e72ebf703..7775ca46d8 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 @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Volo.Abp.MultiTenancy; namespace Volo.Abp.Identity.AspNetCore { @@ -14,7 +13,7 @@ namespace Volo.Abp.Identity.AspNetCore protected AbpIdentityAspNetCoreOptions AbpOptions { get; } public AbpSignInManager( - UserManager userManager, + IdentityUserManager userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory claimsFactory, IOptions optionsAccessor, @@ -51,15 +50,10 @@ namespace Volo.Abp.Identity.AspNetCore if (user == null) { user = await externalLoginProvider.CreateUserAsync(userName); - //TODO: +TenantId, LoginProvider, Password, +NormalizeNames - //TODO: Set default roles - await UserManager.CreateAsync(user); } else { await externalLoginProvider.UpdateUserAsync(user); - //TODO: LoginProvider - await UserManager.UpdateAsync(user); } return await SignInOrTwoFactorAsync(user, isPersistent); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs index c374cbc678..01c6e285a9 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs @@ -32,5 +32,10 @@ namespace Volo.Abp.Identity /// Default value: 256 /// public static int MaxSecurityStampLength { get; set; } = 256; + + /// + /// Default value: 16 + /// + public static int MaxLoginProviderLength { get; set; } = 16; } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs index ea1f5ccf72..1649ce8a76 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs @@ -66,6 +66,8 @@ namespace Volo.Abp.Identity [DisableAuditing] public virtual string SecurityStamp { get; protected internal set; } + public virtual string LoginProvider { get; protected set; } + /// /// Gets or sets a telephone number for the user. /// @@ -133,7 +135,11 @@ namespace Volo.Abp.Identity { } - public IdentityUser(Guid id, [NotNull] string userName, [NotNull] string email, Guid? tenantId = null) + public IdentityUser( + Guid id, + [NotNull] string userName, + [NotNull] string email, + Guid? tenantId = null) { Check.NotNull(userName, nameof(userName)); Check.NotNull(email, nameof(email)); @@ -254,7 +260,8 @@ namespace Volo.Abp.Identity Check.NotNull(loginProvider, nameof(loginProvider)); Check.NotNull(providerKey, nameof(providerKey)); - Logins.RemoveAll(userLogin => userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey); + Logins.RemoveAll(userLogin => + userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey); } [CanBeNull] @@ -316,9 +323,43 @@ namespace Volo.Abp.Identity ); } + public virtual void SetLoginProvider([CanBeNull] string loginProvider) + { + LoginProvider = Check.Length(loginProvider, nameof(loginProvider), + IdentityUserConsts.MaxLoginProviderLength); + } + + /// + /// Use for regular email confirmation. + /// Using this skips the confirmation process and directly sets the . + /// + public virtual void SetEmailConfirmed(bool confirmed) + { + EmailConfirmed = confirmed; + } + + public virtual void SetPhoneNumberConfirmed(bool confirmed) + { + PhoneNumberConfirmed = confirmed; + } + public override string ToString() { return $"{base.ToString()}, UserName = {UserName}"; } + + /// + /// Normally use to change the phone number + /// in the application code. + /// This method is to directly set it with a confirmation information. + /// + /// + /// + /// + public void SetPhoneNumber(string phoneNumber, bool confirmed) + { + PhoneNumber = phoneNumber; + PhoneNumberConfirmed = !phoneNumber.IsNullOrWhiteSpace() && confirmed; + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs index 81269adf5a..17a0fbd39d 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs @@ -291,7 +291,7 @@ namespace Volo.Abp.Identity /// /// The user to retrieve the password hash for. /// The used to propagate notifications that the operation should be canceled. - /// A containing a flag indicating if the specified user has a password. If the + /// A containing a flag indicating if the specified user has a password. If the /// user has a password the returned value with be true, otherwise it will be false. public virtual Task HasPasswordAsync([NotNull] IdentityUser user, CancellationToken cancellationToken = default) { @@ -326,7 +326,7 @@ namespace Volo.Abp.Identity { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Role {0} does not exist!", normalizedRoleName)); } - + await UserRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken); user.AddRole(role.Id); @@ -353,7 +353,7 @@ namespace Volo.Abp.Identity } await UserRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken); - + user.RemoveRole(role.Id); } @@ -384,15 +384,15 @@ namespace Volo.Abp.Identity /// The user whose role membership should be checked. /// The role to check membership of /// The used to propagate notifications that the operation should be canceled. - /// A containing a flag indicating if the specified user is a member of the given group. If the + /// A containing a flag indicating if the specified user is a member of the given group. If the /// user is a member of the group the returned value with be true, otherwise it will be false. public virtual async Task IsInRoleAsync( - [NotNull] IdentityUser user, + [NotNull] IdentityUser user, [NotNull] string normalizedRoleName, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - + Check.NotNull(user, nameof(user)); Check.NotNullOrWhiteSpace(normalizedRoleName, nameof(normalizedRoleName)); @@ -589,7 +589,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - user.EmailConfirmed = confirmed; + user.SetEmailConfirmed(confirmed); return Task.CompletedTask; } @@ -864,7 +864,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - user.PhoneNumberConfirmed = confirmed; + user.SetPhoneNumberConfirmed(confirmed); return Task.CompletedTask; } @@ -928,7 +928,7 @@ namespace Volo.Abp.Identity /// The user whose two factor authentication enabled status should be set. /// The used to propagate notifications that the operation should be canceled. /// - /// The that represents the asynchronous operation, containing a flag indicating whether the specified + /// The that represents the asynchronous operation, containing a flag indicating whether the specified /// has two factor authentication enabled or not. /// public virtual Task GetTwoFactorEnabledAsync([NotNull] IdentityUser user, CancellationToken cancellationToken = default) @@ -946,7 +946,7 @@ namespace Volo.Abp.Identity /// The claim whose users should be retrieved. /// The used to propagate notifications that the operation should be canceled. /// - /// The contains a list of users, if any, that contain the specified claim. + /// The contains a list of users, if any, that contain the specified claim. /// public virtual async Task> GetUsersForClaimAsync([NotNull] Claim claim, CancellationToken cancellationToken = default) { @@ -963,7 +963,7 @@ namespace Volo.Abp.Identity /// The role whose users should be retrieved. /// The used to propagate notifications that the operation should be canceled. /// - /// The contains a list of users, if any, that are in the specified role. + /// The contains a list of users, if any, that are in the specified role. /// public virtual async Task> GetUsersInRoleAsync([NotNull] string normalizedRoleName, CancellationToken cancellationToken = default) { diff --git a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/FakeExternalLoginProvider.cs b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/FakeExternalLoginProvider.cs index 64277765d2..409a0e1e24 100644 --- a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/FakeExternalLoginProvider.cs +++ b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/FakeExternalLoginProvider.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; @@ -10,10 +11,14 @@ namespace Volo.Abp.Identity.AspNetCore public const string Name = "Fake"; private readonly ICurrentTenant _currentTenant; + private readonly IdentityUserManager _userManager; + private RandomPasswordGenerator _randomPasswordGenerator; - public FakeExternalLoginProvider(ICurrentTenant currentTenant) + public FakeExternalLoginProvider(ICurrentTenant currentTenant, IdentityUserManager userManager, RandomPasswordGenerator randomPasswordGenerator) { _currentTenant = currentTenant; + _userManager = userManager; + _randomPasswordGenerator = randomPasswordGenerator; } public override Task TryAuthenticateAsync(string userName, string plainPassword) @@ -23,16 +28,28 @@ namespace Volo.Abp.Identity.AspNetCore ); } - public override Task CreateUserAsync(string userName) + public override async Task CreateUserAsync(string userName) { - return Task.FromResult( - new IdentityUser( - Guid.NewGuid(), - userName, - "test@abp.io", - tenantId: _currentTenant.Id - ) + var user = new IdentityUser( + Guid.NewGuid(), + userName, + "test@abp.io", + tenantId: _currentTenant.Id //Setting TenantId is responsibility of the provider! ); + + user.SetLoginProvider(Name); + user.SetEmailConfirmed(true); //Setting this is responsibility of the provider! + user.SetPhoneNumber("123123", true); + + (await _userManager.CreateAsync(user, await _randomPasswordGenerator.CreateAsync())).CheckErrors(); + (await _userManager.AddDefaultRolesAsync(user)).CheckErrors(); + + return user; + } + + public override async Task UpdateUserAsync(IdentityUser user) + { + (await _userManager.SetEmailAsync(user, "test-updated@abp.io")).CheckErrors(); } } }