Add IdentityLinkUser aggregate root to Identity module.

pull/5190/head
maliming 5 years ago
parent c34c562c5e
commit d044255516

@ -29,11 +29,12 @@ namespace Microsoft.Extensions.DependencyInjection
//AbpRoleStore
services.TryAddScoped<IdentityRoleStore>();
services.TryAddScoped(typeof(IRoleStore<IdentityRole>), provider => provider.GetService(typeof(IdentityRoleStore)));
return services
.AddIdentityCore<IdentityUser>(setupAction)
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<AbpUserClaimsPrincipalFactory>();
.AddClaimsPrincipalFactory<AbpUserClaimsPrincipalFactory>()
.AddTokenProvider<LinkUserTokenProvider>(LinkUserTokenProvider.LinkUserTokenProviderName);
}
}
}

@ -4,22 +4,31 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
using Volo.Abp.Uow;
using Volo.Abp.Users;
namespace Volo.Abp.Identity
{
public class AbpUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<IdentityUser, IdentityRole>, ITransientDependency
{
protected ICurrentImpersonatorUser CurrentImpersonatorUser { get; }
protected ICurrentImpersonatorTenant CurrentImpersonatorTenant { get; }
public AbpUserClaimsPrincipalFactory(
UserManager<IdentityUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> options)
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> options,
ICurrentImpersonatorUser currentImpersonatorUser,
ICurrentImpersonatorTenant currentImpersonatorTenant)
: base(
userManager,
roleManager,
userManager,
roleManager,
options)
{
CurrentImpersonatorUser = currentImpersonatorUser;
CurrentImpersonatorTenant = currentImpersonatorTenant;
}
[UnitOfWork]
@ -34,6 +43,23 @@ namespace Volo.Abp.Identity
.AddClaim(new Claim(AbpClaimTypes.TenantId, user.TenantId.ToString()));
}
if (CurrentImpersonatorUser.Id != user.Id || CurrentImpersonatorTenant.Id != user.TenantId)
{
if (CurrentImpersonatorUser.Id.HasValue)
{
principal.Identities
.First()
.AddClaim(new Claim(AbpClaimTypes.ImpersonatorUserId, CurrentImpersonatorUser.Id.ToString()));
}
if (CurrentImpersonatorTenant.Id.HasValue)
{
principal.Identities
.First()
.AddClaim(new Claim(AbpClaimTypes.ImpersonatorTenantId, CurrentImpersonatorTenant.Id.ToString()));
}
}
return principal;
}
}

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.Identity
{
public interface IIdentityLinkUserRepository : IBasicRepository<IdentityLinkUser, Guid>
{
Task<IdentityLinkUser> FindAsync(
IdentityLinkUserInfo sourceLinkUserInfo,
IdentityLinkUserInfo targetLinkUserInfo,
CancellationToken cancellationToken = default);
Task<List<IdentityLinkUser>> GetListAsync(
IdentityLinkUserInfo linkUserInfo,
CancellationToken cancellationToken = default);
}
}

@ -0,0 +1,36 @@
using System;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.Identity
{
public class IdentityLinkUser : AggregateRoot<Guid>
{
public IdentityLinkUser(Guid id, IdentityLinkUserInfo sourceUser, IdentityLinkUserInfo targetUser)
: base(id)
{
SourceUserId = sourceUser.UserId;
SourceTenantId = sourceUser.TenantId;
TargetUserId = targetUser.UserId;
TargetTenantId = targetUser.TenantId;
}
public IdentityLinkUser(Guid id, Guid sourceUserId, Guid? sourceTenantId, Guid targetUserId, Guid? targetTenantId)
: base(id)
{
SourceUserId = sourceUserId;
SourceTenantId = sourceTenantId;
TargetUserId = targetUserId;
TargetTenantId = targetTenantId;
}
public virtual Guid SourceUserId { get; protected set; }
public virtual Guid? SourceTenantId { get; protected set; }
public virtual Guid TargetUserId { get; protected set; }
public virtual Guid? TargetTenantId { get; protected set; }
}
}

@ -0,0 +1,17 @@
using System;
namespace Volo.Abp.Identity
{
public class IdentityLinkUserInfo
{
public virtual Guid UserId { get; set; }
public virtual Guid? TenantId { get; set; }
public IdentityLinkUserInfo(Guid userId, Guid? tenantId)
{
UserId = userId;
TenantId = tenantId;
}
}
}

@ -0,0 +1,86 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Identity
{
public class IdentityLinkUserManager : DomainService
{
protected IIdentityLinkUserRepository IdentityLinkUserRepository { get; }
protected IdentityUserManager UserManager { get; }
protected new ICurrentTenant CurrentTenant { get; }
public IdentityLinkUserManager(IIdentityLinkUserRepository identityLinkUserRepository, IdentityUserManager userManager, ICurrentTenant currentTenant)
{
IdentityLinkUserRepository = identityLinkUserRepository;
UserManager = userManager;
CurrentTenant = currentTenant;
}
public virtual async Task LinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser)
{
if (sourceLinkUser.UserId == targetLinkUser.UserId && sourceLinkUser.TenantId == targetLinkUser.TenantId)
{
return;
}
if (await IsLinkedAsync(sourceLinkUser, targetLinkUser))
{
return;
}
var userLink = new IdentityLinkUser(
GuidGenerator.Create(),
sourceLinkUser,
targetLinkUser);
await IdentityLinkUserRepository.InsertAsync(userLink, true);
}
public virtual async Task<bool> IsLinkedAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser)
{
return await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser) != null;
}
public virtual async Task UnlinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser)
{
if (!await IsLinkedAsync(sourceLinkUser, targetLinkUser))
{
return;
}
var linkedUser = await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser);
if (linkedUser != null)
{
await IdentityLinkUserRepository.DeleteAsync(linkedUser);
}
}
public virtual async Task<string> GenerateLinkTokenAsync(IdentityLinkUserInfo targetLinkUser)
{
using (CurrentTenant.Change(targetLinkUser.TenantId))
{
var user = await UserManager.GetByIdAsync(targetLinkUser.UserId);
return await UserManager.GenerateUserTokenAsync(
user,
LinkUserTokenProvider.LinkUserTokenProviderName,
LinkUserTokenProvider.LinkUserTokenPurpose);
}
}
public virtual async Task<bool> VerifyLinkTokenAsync(IdentityLinkUserInfo targetLinkUser, string token)
{
using (CurrentTenant.Change(targetLinkUser.TenantId))
{
var user = await UserManager.GetByIdAsync(targetLinkUser.UserId);
return await UserManager.VerifyUserTokenAsync(
user,
LinkUserTokenProvider.LinkUserTokenProviderName,
LinkUserTokenProvider.LinkUserTokenPurpose,
token);
}
}
}
}

@ -0,0 +1,17 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace Volo.Abp.Identity
{
public class LinkUserTokenProvider : TotpSecurityStampBasedTokenProvider<IdentityUser>
{
public const string LinkUserTokenProviderName = "AbpLinkUser";
public const string LinkUserTokenPurpose = "AbpLinkUserLogin";
public override Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<IdentityUser> manager, IdentityUser user)
{
return Task.FromResult(false);
}
}
}

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.Identity.EntityFrameworkCore
{
public class EfCoreIdentityLinkUserRepository : EfCoreRepository<IIdentityDbContext, IdentityLinkUser, Guid>, IIdentityLinkUserRepository
{
public EfCoreIdentityLinkUserRepository(IDbContextProvider<IIdentityDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<IdentityLinkUser> FindAsync(IdentityLinkUserInfo sourceLinkUserInfo, IdentityLinkUserInfo targetLinkUserInfo, CancellationToken cancellationToken = default)
{
return await DbSet.FirstOrDefaultAsync(x =>
x.SourceUserId == sourceLinkUserInfo.UserId && x.SourceTenantId == sourceLinkUserInfo.TenantId &&
x.TargetUserId == targetLinkUserInfo.UserId && x.TargetTenantId == targetLinkUserInfo.TenantId ||
x.TargetUserId == sourceLinkUserInfo.UserId && x.TargetTenantId == sourceLinkUserInfo.TenantId &&
x.SourceUserId == targetLinkUserInfo.UserId && x.SourceTenantId == targetLinkUserInfo.TenantId
, cancellationToken: GetCancellationToken(cancellationToken));
}
public async Task<List<IdentityLinkUser>> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default)
{
return await DbSet.Where(x =>
x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId ||
x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId)
.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken));
}
}
}

@ -17,5 +17,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
DbSet<OrganizationUnit> OrganizationUnits { get; set; }
DbSet<IdentitySecurityLog> IdentitySecurityLogs { get; set; }
DbSet<IdentityLinkUser> IdentityLinkUsers { get; set; }
}
}

@ -20,6 +20,8 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
public DbSet<IdentitySecurityLog> IdentitySecurityLogs { get; set; }
public DbSet<IdentityLinkUser> IdentityLinkUsers { get; set; }
public IdentityDbContext(DbContextOptions<IdentityDbContext> options)
: base(options)
{

@ -233,6 +233,22 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
b.HasIndex(x => new { x.TenantId, x.UserId });
});
builder.Entity<IdentityLinkUser>(b =>
{
b.ToTable(options.TablePrefix + "LinkUsers", options.Schema);
b.ConfigureByConvention();
b.HasIndex(x => new
{
UserId = x.SourceUserId,
TenantId = x.SourceTenantId,
LinkedUserId = x.TargetUserId,
LinkedTenantId = x.TargetTenantId
}).IsUnique();
});
}
}
}

@ -17,6 +17,8 @@ namespace Volo.Abp.Identity.MongoDB
public IMongoCollection<IdentitySecurityLog> IdentitySecurityLogs => Collection<IdentitySecurityLog>();
public IMongoCollection<IdentityLinkUser> IdentityLinkUsers => Collection<IdentityLinkUser>();
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);

@ -41,6 +41,11 @@ namespace Volo.Abp.Identity.MongoDB
{
b.CollectionName = options.CollectionPrefix + "SecurityLogs";
});
builder.Entity<IdentityLinkUser>(b =>
{
b.CollectionName = options.CollectionPrefix + "LinkUsers";
});
}
}
}

@ -19,6 +19,7 @@ namespace Volo.Abp.Identity.MongoDB
options.AddRepository<IdentityClaimType, MongoIdentityRoleRepository>();
options.AddRepository<OrganizationUnit, MongoIdentityRoleRepository>();
options.AddRepository<IdentitySecurityLog, MongoIdentitySecurityLogRepository>();
options.AddRepository<IdentityLinkUser, MongoIdentityLinkUserRepository>();
});
}
}

@ -16,5 +16,7 @@ namespace Volo.Abp.Identity.MongoDB
IMongoCollection<OrganizationUnit> OrganizationUnits { get; }
IMongoCollection<IdentitySecurityLog> IdentitySecurityLogs { get; }
IMongoCollection<IdentityLinkUser> IdentityLinkUsers { get; }
}
}

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
namespace Volo.Abp.Identity.MongoDB
{
public class MongoIdentityLinkUserRepository : MongoDbRepository<IAbpIdentityMongoDbContext, IdentityLinkUser, Guid>, IIdentityLinkUserRepository
{
public MongoIdentityLinkUserRepository(IMongoDbContextProvider<IAbpIdentityMongoDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public async Task<IdentityLinkUser> FindAsync(IdentityLinkUserInfo sourceLinkUserInfo, IdentityLinkUserInfo targetLinkUserInfo, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().FirstOrDefaultAsync(x =>
x.SourceUserId == sourceLinkUserInfo.UserId && x.SourceTenantId == sourceLinkUserInfo.TenantId &&
x.TargetUserId == targetLinkUserInfo.UserId && x.TargetTenantId == targetLinkUserInfo.TenantId ||
x.TargetUserId == sourceLinkUserInfo.UserId && x.TargetTenantId == sourceLinkUserInfo.TenantId &&
x.SourceUserId == targetLinkUserInfo.UserId && x.SourceTenantId == targetLinkUserInfo.TenantId
, cancellationToken: GetCancellationToken(cancellationToken));
}
public async Task<List<IdentityLinkUser>> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().Where(x =>
x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId ||
x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId)
.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken));
}
}
}

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Shouldly;
using Xunit;
namespace Volo.Abp.Identity.AspNetCore
{
public class LinkUserTokenProvider_Tests : AbpIdentityAspNetCoreTestBase
{
[Fact]
public void LinkUserTokenProvider_Should_Be_Register()
{
var identityOptions = GetRequiredService<IOptions<IdentityOptions>>().Value;
identityOptions.Tokens.ProviderMap.ShouldContain(x =>
x.Key == LinkUserTokenProvider.LinkUserTokenProviderName &&
x.Value.ProviderType == typeof(LinkUserTokenProvider));
}
}
}

@ -0,0 +1,86 @@
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace Volo.Abp.Identity
{
public class IdentityLinkUserManager_Tests : AbpIdentityDomainTestBase
{
protected IIdentityUserRepository UserRepository { get; }
protected IIdentityLinkUserRepository IdentityLinkUserRepository { get; }
protected IdentityLinkUserManager IdentityLinkUserManager { get; }
protected IdentityTestData TestData { get; }
public IdentityLinkUserManager_Tests()
{
UserRepository = GetRequiredService<IIdentityUserRepository>();
IdentityLinkUserRepository = GetRequiredService<IIdentityLinkUserRepository>();
IdentityLinkUserManager = GetRequiredService<IdentityLinkUserManager>();
TestData = GetRequiredService<IdentityTestData>();
}
[Fact]
public virtual async Task LinkAsync()
{
var john = await UserRepository.GetAsync(TestData.UserJohnId);
var neo = await UserRepository.GetAsync(TestData.UserNeoId);
(await IdentityLinkUserRepository.FindAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(neo.Id, neo.TenantId))).ShouldBeNull();
await IdentityLinkUserManager.LinkAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(neo.Id, neo.TenantId));
var linkUser = await IdentityLinkUserRepository.FindAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(neo.Id, neo.TenantId));
linkUser.ShouldNotBeNull();
linkUser.SourceUserId.ShouldBe(john.Id);
linkUser.SourceTenantId.ShouldBe(john.TenantId);
linkUser.TargetUserId.ShouldBe(neo.Id);
linkUser.TargetTenantId.ShouldBe(neo.TenantId);
}
[Fact]
public virtual async Task UnlinkAsync()
{
var john = await UserRepository.GetAsync(TestData.UserJohnId);
var david = await UserRepository.GetAsync(TestData.UserDavidId);
(await IdentityLinkUserRepository.FindAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(david.Id, david.TenantId))).ShouldNotBeNull();
await IdentityLinkUserManager.UnlinkAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(david.Id, david.TenantId));
(await IdentityLinkUserRepository.FindAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(david.Id, david.TenantId))).ShouldBeNull();
}
[Fact]
public virtual async Task IsLinkedAsync()
{
var john = await UserRepository.GetAsync(TestData.UserJohnId);
var david = await UserRepository.GetAsync(TestData.UserDavidId);
var neo = await UserRepository.GetAsync(TestData.UserNeoId);
(await IdentityLinkUserManager.IsLinkedAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(david.Id, david.TenantId))).ShouldBeTrue();
(await IdentityLinkUserManager.IsLinkedAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(neo.Id, neo.TenantId))).ShouldBeFalse();
}
[Fact]
public virtual async Task GenerateAndVerifyLinkTokenAsync()
{
var john = await UserRepository.GetAsync(TestData.UserJohnId);
var token = await IdentityLinkUserManager.GenerateLinkTokenAsync(new IdentityLinkUserInfo(john.Id, john.TenantId));
(await IdentityLinkUserManager.VerifyLinkTokenAsync(new IdentityLinkUserInfo(john.Id, john.TenantId), token)).ShouldBeTrue();
(await IdentityLinkUserManager.VerifyLinkTokenAsync(new IdentityLinkUserInfo(john.Id, john.TenantId), "123123")).ShouldBeFalse();
}
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.Identity.EntityFrameworkCore
{
public class IdentityLinkUserRepository_Tests : IdentityLinkUserRepository_Tests<AbpIdentityEntityFrameworkCoreTestModule>
{
}
}

@ -0,0 +1,10 @@
using Xunit;
namespace Volo.Abp.Identity.MongoDB
{
[Collection(MongoTestCollection.Name)]
public class IdentityLinkUserRepository_Tests : IdentityLinkUserRepository_Tests<AbpIdentityMongoDbTestModule>
{
}
}

@ -19,6 +19,8 @@ namespace Volo.Abp.Identity
private readonly ILookupNormalizer _lookupNormalizer;
private readonly IdentityTestData _testData;
private readonly OrganizationUnitManager _organizationUnitManager;
private readonly IIdentityLinkUserRepository _identityLinkUserRepository;
private readonly IdentityLinkUserManager _identityLinkUserManager;
private IdentityRole _adminRole;
private IdentityRole _moderatorRole;
@ -36,7 +38,9 @@ namespace Volo.Abp.Identity
IIdentitySecurityLogRepository identitySecurityLogRepository,
ILookupNormalizer lookupNormalizer,
IdentityTestData testData,
OrganizationUnitManager organizationUnitManager)
OrganizationUnitManager organizationUnitManager,
IIdentityLinkUserRepository identityLinkUserRepository,
IdentityLinkUserManager identityLinkUserManager)
{
_guidGenerator = guidGenerator;
_userRepository = userRepository;
@ -46,6 +50,8 @@ namespace Volo.Abp.Identity
_testData = testData;
_organizationUnitRepository = organizationUnitRepository;
_organizationUnitManager = organizationUnitManager;
_identityLinkUserRepository = identityLinkUserRepository;
_identityLinkUserManager = identityLinkUserManager;
_identitySecurityLogRepository = identitySecurityLogRepository;
}
@ -54,6 +60,7 @@ namespace Volo.Abp.Identity
await AddRoles();
await AddOrganizationUnits();
await AddUsers();
await AddLinkUsers();
await AddClaimTypes();
await AddSecurityLogs();
}
@ -128,6 +135,17 @@ namespace Volo.Abp.Identity
await _userRepository.InsertAsync(neo);
}
private async Task AddLinkUsers()
{
var john = await _userRepository.GetAsync(_testData.UserJohnId);
var david = await _userRepository.GetAsync(_testData.UserDavidId);
var neo = await _userRepository.GetAsync(_testData.UserNeoId);
await _identityLinkUserManager.LinkAsync(new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(david.Id, david.TenantId));
await _identityLinkUserManager.LinkAsync(new IdentityLinkUserInfo(david.Id, david.TenantId),
new IdentityLinkUserInfo(neo.Id, neo.TenantId));
}
private async Task AddClaimTypes()
{

@ -0,0 +1,58 @@
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.Identity
{
public abstract class IdentityLinkUserRepository_Tests<TStartupModule> : AbpIdentityTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
protected IIdentityUserRepository UserRepository { get; }
protected IIdentityLinkUserRepository IdentityLinkUserRepository { get; }
protected IdentityTestData TestData { get; }
public IdentityLinkUserRepository_Tests()
{
UserRepository = GetRequiredService<IIdentityUserRepository>();
IdentityLinkUserRepository = GetRequiredService<IIdentityLinkUserRepository>();
TestData = GetRequiredService<IdentityTestData>();
}
[Fact]
public async Task FindAsync()
{
var john = await UserRepository.GetAsync(TestData.UserJohnId);
var david = await UserRepository.GetAsync(TestData.UserDavidId);
var neo = await UserRepository.GetAsync(TestData.UserNeoId);
var johnAndDavidLinkUser = await IdentityLinkUserRepository.FindAsync(
new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(david.Id, david.TenantId));
johnAndDavidLinkUser.ShouldNotBeNull();
johnAndDavidLinkUser.SourceUserId.ShouldBe(john.Id);
johnAndDavidLinkUser.SourceTenantId.ShouldBe(john.TenantId);
johnAndDavidLinkUser.TargetUserId.ShouldBe(david.Id);
johnAndDavidLinkUser.TargetTenantId.ShouldBe(david.TenantId);
(await IdentityLinkUserRepository.FindAsync(
new IdentityLinkUserInfo(john.Id, john.TenantId),
new IdentityLinkUserInfo(neo.Id, neo.TenantId))).ShouldBeNull();
}
[Fact]
public async Task GetListAsync()
{
var john = await UserRepository.GetAsync(TestData.UserJohnId);
var david = await UserRepository.GetAsync(TestData.UserDavidId);
var neo = await UserRepository.GetAsync(TestData.UserNeoId);
var davidLinkUsers = await IdentityLinkUserRepository.GetListAsync(new IdentityLinkUserInfo(david.Id, david.TenantId));
davidLinkUsers.ShouldNotBeNull();
davidLinkUsers.ShouldContain(x => x.SourceUserId == john.Id && x.SourceTenantId == john.TenantId);
davidLinkUsers.ShouldContain(x => x.TargetUserId == neo.Id && x.TargetTenantId == neo.TenantId);
}
}
}
Loading…
Cancel
Save