Browse Source

Add multi-tenant external login support for IdentityUser

pull/24456/head
maliming 9 months ago
parent
commit
d51a767151
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 21
      modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs
  2. 18
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityUserValidator.cs
  3. 7
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs
  4. 30
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs
  5. 9
      modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs
  6. 8
      modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs

21
modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs

@ -91,6 +91,22 @@ public class AbpSignInManager : SignInManager<IdentityUser>
return await PasswordSignInAsync(user, password, isPersistent, lockoutOnFailure);
}
public override async Task<SignInResult> ExternalLoginSignInAsync(string loginProvider, string providerKey, bool isPersistent, bool bypassTwoFactor)
{
var user = await FindByLoginAsync(loginProvider, providerKey);
if (user == null)
{
return SignInResult.Failed;
}
var error = await PreSignInCheck(user);
if (error != null)
{
return error;
}
return await SignInOrTwoFactorAsync(user, isPersistent, loginProvider, bypassTwoFactor);
}
public virtual async Task<IdentityUser> FindByEmaiAsync(string email)
{
return await _identityUserManager.FindByEmailInHostAsync(email);
@ -101,6 +117,11 @@ public class AbpSignInManager : SignInManager<IdentityUser>
return await _identityUserManager.FindByNameInHostAsync(userName);
}
public virtual async Task<IdentityUser> FindByLoginAsync(string loginProvider, string providerKey)
{
return await _identityUserManager.FindByLoginInHostAsync(loginProvider, providerKey);
}
/// <summary>
/// This is to call the protection method PreSignInCheck
/// </summary>

18
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityUserValidator.cs

@ -170,10 +170,15 @@ namespace Volo.Abp.Identity
}
else
{
var owner = await manager.FindByNameAsync(userName);
IdentityUser owner;
using (CurrentTenant.Change(user.TenantId))
{
owner = await manager.FindByNameAsync(userName);
}
if (owner != null &&
!string.Equals(await manager.GetUserIdAsync(owner), await manager.GetUserIdAsync(user)) &&
owner.TenantId == user.TenantId)
owner.TenantId == user.TenantId &&
owner.NormalizedUserName != manager.NormalizeName(userName))
{
errors.Add(ErrorDescriber.DuplicateUserName(userName));
}
@ -197,10 +202,15 @@ namespace Volo.Abp.Identity
errors.Add(ErrorDescriber.InvalidEmail(email));
return errors;
}
var owner = await manager.FindByEmailAsync(email);
IdentityUser owner;
using (CurrentTenant.Change(user.TenantId))
{
owner = await manager.FindByEmailAsync(email);
}
if (owner != null &&
!string.Equals(await manager.GetUserIdAsync(owner), await manager.GetUserIdAsync(user)) &&
owner.TenantId == user.TenantId)
owner.TenantId == user.TenantId &&
owner.NormalizedEmail != manager.NormalizeEmail(email))
{
errors.Add(ErrorDescriber.DuplicateEmail(email));
}

7
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs

@ -190,6 +190,13 @@ public interface IIdentityUserRepository : IBasicRepository<IdentityUser, Guid>
CancellationToken cancellationToken = default
);
Task<List<IdentityUser>> GetUsersByLoginAsync(
[NotNull] string loginProvider,
[NotNull] string providerKey,
bool includeDetails = false,
CancellationToken cancellationToken = default
);
Task<IdentityUser> FindByNormalizedUserNameAsync(
Guid? tenantId,
[NotNull] string normalizedUserName,

30
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs

@ -657,4 +657,34 @@ public class IdentityUserManager : UserManager<IdentityUser>, IDomainService
}
}
}
public virtual async Task<IdentityUser> FindByLoginInHostAsync(string loginProvider, string providerKey)
{
if (MultiTenancyOptions.Value.UserSharingStrategy == TenantUserSharingStrategy.Isolated)
{
return await base.FindByLoginAsync(loginProvider, providerKey);
}
using (CurrentTenant.Change(null))
{
using (DataFilter.Disable<IMultiTenant>())
{
var hostusers = await UserRepository.GetUsersByLoginAsync(loginProvider, providerKey, cancellationToken: CancellationToken);
//host user first
var hostUser = hostusers.FirstOrDefault(x => x.TenantId == null) ?? hostusers.FirstOrDefault();
if (hostUser == null)
{
return null;
}
using (DataFilter.Enable<IMultiTenant>())
{
using (CurrentTenant.Change(hostUser.TenantId))
{
return await base.FindByLoginAsync(loginProvider, providerKey);
}
}
}
}
}
}

9
modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs

@ -493,6 +493,15 @@ public class EfCoreIdentityUserRepository : EfCoreRepository<IIdentityDbContext,
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<IdentityUser>> GetUsersByLoginAsync(string loginProvider, string providerKey, bool includeDetails = false, CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.IncludeDetails(includeDetails)
.OrderBy(x => x.Id)
.Where(u => u.Logins.Any(login => login.LoginProvider == loginProvider && login.ProviderKey == providerKey))
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<IdentityUser> FindByNormalizedUserNameAsync(Guid? tenantId, string normalizedUserName, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())

8
modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs

@ -485,6 +485,14 @@ public class MongoIdentityUserRepository : MongoDbRepository<IAbpIdentityMongoDb
.ToListAsync(cancellationToken: cancellationToken);
}
public virtual async Task<List<IdentityUser>> GetUsersByLoginAsync(string loginProvider, string providerKey, bool includeDetails = false, CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync(cancellationToken))
.OrderBy(x => x.Id)
.Where(u => u.Logins.Any(login => login.LoginProvider == loginProvider && login.ProviderKey == providerKey))
.ToListAsync(cancellationToken: cancellationToken);
}
public virtual async Task<IdentityUser> FindByNormalizedUserNameAsync(Guid? tenantId, string normalizedUserName, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync(cancellationToken))

Loading…
Cancel
Save