From c90960395cf9205796bfb6b23cf22143a300e967 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 5 Mar 2021 11:51:55 +0800 Subject: [PATCH 1/6] Link users enhancements. --- .../Identity/IIdentityLinkUserRepository.cs | 7 +- .../Abp/Identity/IdentityUserLinkManager.cs | 49 ++++++++ .../EfCoreIdentityLinkUserRepository.cs | 28 ++++- .../MongoIdentityLinkUserRepository.cs | 29 ++++- .../Identity/IdentityLinkUserManager_Tests.cs | 119 +++++++++++++++++- .../IdentityLinkUserRepository_Tests.cs | 24 +++- 6 files changed, 246 insertions(+), 10 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityLinkUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityLinkUserRepository.cs index 2040924d10..9e86d4b34b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityLinkUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityLinkUserRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -14,6 +14,11 @@ namespace Volo.Abp.Identity CancellationToken cancellationToken = default); Task> GetListAsync( + IdentityLinkUserInfo linkUserInfo, + List excludes = null, + CancellationToken cancellationToken = default); + + Task DeleteAsync( IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs index 6f8c600daa..967296bc28 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Services; using Volo.Abp.MultiTenancy; @@ -20,6 +23,52 @@ namespace Volo.Abp.Identity CurrentTenant = currentTenant; } + public async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, + bool includeIndirect = false, CancellationToken cancellationToken = default) + { + var users = await IdentityLinkUserRepository.GetListAsync(linkUserInfo, cancellationToken: cancellationToken); + if (includeIndirect == false) + { + return users; + } + + var userInfos = new List() + { + linkUserInfo + }; + + var allUsers = new List(); + allUsers.AddRange(users); + + do + { + var nextUsers = new List(); + foreach (var user in users) + { + if (userInfos.Any(x => x.TenantId != user.SourceTenantId || x.UserId != user.SourceUserId)) + { + nextUsers.Add(new IdentityLinkUserInfo(user.SourceUserId, user.SourceTenantId)); + } + + if (userInfos.Any(x => x.TenantId != user.TargetTenantId || x.UserId != user.TargetUserId)) + { + nextUsers.Add(new IdentityLinkUserInfo(user.TargetUserId, user.TargetTenantId)); + } + } + + users = new List(); + foreach (var next in nextUsers) + { + users.AddRange(await IdentityLinkUserRepository.GetListAsync(next, userInfos, cancellationToken: cancellationToken)); + } + + userInfos.AddRange(nextUsers); + allUsers.AddRange(users); + } while (users.Any()); + + return allUsers; + } + public virtual async Task LinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser) { if (sourceLinkUser.UserId == targetLinkUser.UserId && sourceLinkUser.TenantId == targetLinkUser.TenantId) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs index c7e81f327e..ab76f0cc48 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -28,13 +28,35 @@ namespace Volo.Abp.Identity.EntityFrameworkCore , cancellationToken: GetCancellationToken(cancellationToken)); } - public virtual async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, List excludes = null, + CancellationToken cancellationToken = default) { - return await (await GetDbSetAsync()) + IQueryable query = (await GetDbSetAsync()) .Where(x => + x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || + x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId); + + if (!excludes.IsNullOrEmpty()) + { + foreach (var userInfo in excludes) + { + query = query.Where(x => + (x.SourceTenantId != userInfo.TenantId || x.SourceUserId != userInfo.UserId) && + (x.TargetTenantId != userInfo.TenantId || x.TargetUserId != userInfo.UserId)); + } + } + + return await query.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); + } + + public virtual async Task DeleteAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default) + { + var linkUsers = await (await GetDbSetAsync()).Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); + + await DeleteManyAsync(linkUsers, cancellationToken: cancellationToken); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs index e670759e5c..bb30103dfc 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs @@ -1,7 +1,6 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; @@ -28,12 +27,34 @@ namespace Volo.Abp.Identity.MongoDB , cancellationToken: GetCancellationToken(cancellationToken)); } - public virtual async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, List excludes = null, + CancellationToken cancellationToken = default) { - return await (await GetMongoQueryableAsync(cancellationToken)).Where(x => + var query = (await GetMongoQueryableAsync(cancellationToken)).Where(x => + x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || + x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId); + + if (!excludes.IsNullOrEmpty()) + { + foreach (var userInfo in excludes) + { + query = query.Where(x => + (x.SourceTenantId != userInfo.TenantId || x.SourceUserId != userInfo.UserId) && + (x.TargetTenantId != userInfo.TenantId || x.TargetUserId != userInfo.UserId)); + } + } + + return await query.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); + } + + public virtual async Task DeleteAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default) + { + var linkUsers = await (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); + + await DeleteManyAsync(linkUsers, cancellationToken: cancellationToken); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs index 633f419da5..4bb77cad67 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Shouldly; using Xunit; @@ -19,6 +20,122 @@ namespace Volo.Abp.Identity TestData = GetRequiredService(); } + [Fact] + public async Task GetListAsync_Test() + { + var a = Guid.NewGuid(); + var b = Guid.NewGuid(); + var c = Guid.NewGuid(); + var d = Guid.NewGuid(); + var e = Guid.NewGuid(); + var f = Guid.NewGuid(); + var g = Guid.NewGuid(); + var h = Guid.NewGuid(); + var i = Guid.NewGuid(); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(a, null), + new IdentityLinkUserInfo(b, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(c, null), + new IdentityLinkUserInfo(a, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(d, null), + new IdentityLinkUserInfo(c, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(e, null), + new IdentityLinkUserInfo(c, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(f, null), + new IdentityLinkUserInfo(e, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(g, null), + new IdentityLinkUserInfo(h, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(i, null), + new IdentityLinkUserInfo(h, null)), true); + + var linkUsers = await IdentityLinkUserManager.GetListAsync(new IdentityLinkUserInfo(a, null)); + linkUsers.Count.ShouldBe(2); + + linkUsers = await IdentityLinkUserManager.GetListAsync(new IdentityLinkUserInfo(f, null)); + linkUsers.Count.ShouldBe(1); + + linkUsers = await IdentityLinkUserManager.GetListAsync(new IdentityLinkUserInfo(g, null)); + linkUsers.Count.ShouldBe(1); + } + + [Fact] + public async Task GetListAsync_Indirect_Test() + { + var a = Guid.NewGuid(); + var b = Guid.NewGuid(); + var c = Guid.NewGuid(); + var d = Guid.NewGuid(); + var e = Guid.NewGuid(); + var f = Guid.NewGuid(); + var g = Guid.NewGuid(); + var h = Guid.NewGuid(); + var i = Guid.NewGuid(); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(a, null), + new IdentityLinkUserInfo(b, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(c, null), + new IdentityLinkUserInfo(a, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(d, null), + new IdentityLinkUserInfo(c, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(e, null), + new IdentityLinkUserInfo(c, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(f, null), + new IdentityLinkUserInfo(e, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(g, null), + new IdentityLinkUserInfo(h, null)), true); + + await IdentityLinkUserRepository.InsertAsync(new IdentityLinkUser( + Guid.NewGuid(), + new IdentityLinkUserInfo(i, null), + new IdentityLinkUserInfo(h, null)), true); + + var linkUsers = await IdentityLinkUserManager.GetListAsync(new IdentityLinkUserInfo(a, null), includeIndirect: true); + linkUsers.Count.ShouldBe(5); + + linkUsers = await IdentityLinkUserManager.GetListAsync(new IdentityLinkUserInfo(f, null), includeIndirect: true); + linkUsers.Count.ShouldBe(5); + + linkUsers = await IdentityLinkUserManager.GetListAsync(new IdentityLinkUserInfo(g, null), includeIndirect: true); + linkUsers.Count.ShouldBe(2); + } + [Fact] public virtual async Task LinkAsync() { diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityLinkUserRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityLinkUserRepository_Tests.cs index e5dd6dcd5f..64dd9c5d20 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityLinkUserRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityLinkUserRepository_Tests.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Shouldly; using Volo.Abp.Modularity; using Xunit; @@ -54,5 +55,26 @@ namespace Volo.Abp.Identity davidLinkUsers.ShouldContain(x => x.SourceUserId == john.Id && x.SourceTenantId == john.TenantId); davidLinkUsers.ShouldContain(x => x.TargetUserId == neo.Id && x.TargetTenantId == neo.TenantId); } + + [Fact] + public async Task DeleteAsync() + { + 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 IdentityLinkUserRepository.DeleteAsync(new IdentityLinkUserInfo(david.Id, david.TenantId)); + + (await IdentityLinkUserRepository.FindAsync( + new IdentityLinkUserInfo(john.Id, john.TenantId), + new IdentityLinkUserInfo(david.Id, david.TenantId))).ShouldBeNull(); + + (await IdentityLinkUserRepository.FindAsync( + new IdentityLinkUserInfo(david.Id, david.TenantId), + new IdentityLinkUserInfo(john.Id, john.TenantId))).ShouldBeNull(); + } } } From bf9cdbba26620ec641e0b7d1cf423b3c934e144f Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 5 Mar 2021 12:34:20 +0800 Subject: [PATCH 2/6] Add includeIndirect parameter to IsLinkedAsync method. --- .../Abp/Identity/IdentityUserLinkManager.cs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs index 967296bc28..3e979b6420 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs @@ -23,8 +23,7 @@ namespace Volo.Abp.Identity CurrentTenant = currentTenant; } - public async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, - bool includeIndirect = false, CancellationToken cancellationToken = default) + public async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, bool includeIndirect = false, CancellationToken cancellationToken = default) { var users = await IdentityLinkUserRepository.GetListAsync(linkUserInfo, cancellationToken: cancellationToken); if (includeIndirect == false) @@ -59,7 +58,7 @@ namespace Volo.Abp.Identity users = new List(); foreach (var next in nextUsers) { - users.AddRange(await IdentityLinkUserRepository.GetListAsync(next, userInfos, cancellationToken: cancellationToken)); + users.AddRange(await IdentityLinkUserRepository.GetListAsync(next, userInfos, cancellationToken)); } userInfos.AddRange(nextUsers); @@ -69,14 +68,14 @@ namespace Volo.Abp.Identity return allUsers; } - public virtual async Task LinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser) + public virtual async Task LinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser, CancellationToken cancellationToken = default) { if (sourceLinkUser.UserId == targetLinkUser.UserId && sourceLinkUser.TenantId == targetLinkUser.TenantId) { return; } - if (await IsLinkedAsync(sourceLinkUser, targetLinkUser)) + if (await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken)) { return; } @@ -87,36 +86,42 @@ namespace Volo.Abp.Identity GuidGenerator.Create(), sourceLinkUser, targetLinkUser); - await IdentityLinkUserRepository.InsertAsync(userLink, true); + await IdentityLinkUserRepository.InsertAsync(userLink, true, cancellationToken); } } - public virtual async Task IsLinkedAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser) + public virtual async Task IsLinkedAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser, bool includeIndirect = false, CancellationToken cancellationToken = default) { using (CurrentTenant.Change(null)) { - return await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser) != null; + if (includeIndirect) + { + return (await IdentityLinkUserRepository.GetListAsync(sourceLinkUser, cancellationToken: cancellationToken)) + .Any(x => x.SourceTenantId == targetLinkUser.TenantId && x.SourceUserId == targetLinkUser.UserId || + x.TargetTenantId == targetLinkUser.TenantId && x.TargetUserId == targetLinkUser.UserId); + } + return await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser, cancellationToken) != null; } } - public virtual async Task UnlinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser) + public virtual async Task UnlinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser, CancellationToken cancellationToken = default) { - if (!await IsLinkedAsync(sourceLinkUser, targetLinkUser)) + if (!await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken)) { return; } using (CurrentTenant.Change(null)) { - var linkedUser = await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser); + var linkedUser = await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser, cancellationToken); if (linkedUser != null) { - await IdentityLinkUserRepository.DeleteAsync(linkedUser); + await IdentityLinkUserRepository.DeleteAsync(linkedUser, cancellationToken: cancellationToken); } } } - public virtual async Task GenerateLinkTokenAsync(IdentityLinkUserInfo targetLinkUser) + public virtual async Task GenerateLinkTokenAsync(IdentityLinkUserInfo targetLinkUser, CancellationToken cancellationToken = default) { using (CurrentTenant.Change(targetLinkUser.TenantId)) { @@ -128,7 +133,7 @@ namespace Volo.Abp.Identity } } - public virtual async Task VerifyLinkTokenAsync(IdentityLinkUserInfo targetLinkUser, string token) + public virtual async Task VerifyLinkTokenAsync(IdentityLinkUserInfo targetLinkUser, string token, CancellationToken cancellationToken = default) { using (CurrentTenant.Change(targetLinkUser.TenantId)) { From 6df634bb28e976a6c6e390bbc9c7b76fab02dd46 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 5 Mar 2021 13:04:47 +0800 Subject: [PATCH 3/6] Always change current tenant to host in IdentityLinkUserManager. --- .../Abp/Identity/IdentityUserLinkManager.cs | 94 ++++++++++--------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs index 3e979b6420..d4c89a6ad5 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -25,63 +24,66 @@ namespace Volo.Abp.Identity public async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, bool includeIndirect = false, CancellationToken cancellationToken = default) { - var users = await IdentityLinkUserRepository.GetListAsync(linkUserInfo, cancellationToken: cancellationToken); - if (includeIndirect == false) + using (CurrentTenant.Change(null)) { - return users; - } + var users = await IdentityLinkUserRepository.GetListAsync(linkUserInfo, cancellationToken: cancellationToken); + if (includeIndirect == false) + { + return users; + } - var userInfos = new List() - { - linkUserInfo - }; + var userInfos = new List() + { + linkUserInfo + }; - var allUsers = new List(); - allUsers.AddRange(users); + var allUsers = new List(); + allUsers.AddRange(users); - do - { - var nextUsers = new List(); - foreach (var user in users) + do { - if (userInfos.Any(x => x.TenantId != user.SourceTenantId || x.UserId != user.SourceUserId)) + var nextUsers = new List(); + foreach (var user in users) { - nextUsers.Add(new IdentityLinkUserInfo(user.SourceUserId, user.SourceTenantId)); + if (userInfos.Any(x => x.TenantId != user.SourceTenantId || x.UserId != user.SourceUserId)) + { + nextUsers.Add(new IdentityLinkUserInfo(user.SourceUserId, user.SourceTenantId)); + } + + if (userInfos.Any(x => x.TenantId != user.TargetTenantId || x.UserId != user.TargetUserId)) + { + nextUsers.Add(new IdentityLinkUserInfo(user.TargetUserId, user.TargetTenantId)); + } } - if (userInfos.Any(x => x.TenantId != user.TargetTenantId || x.UserId != user.TargetUserId)) + users = new List(); + foreach (var next in nextUsers) { - nextUsers.Add(new IdentityLinkUserInfo(user.TargetUserId, user.TargetTenantId)); + users.AddRange(await IdentityLinkUserRepository.GetListAsync(next, userInfos, cancellationToken)); } - } - users = new List(); - foreach (var next in nextUsers) - { - users.AddRange(await IdentityLinkUserRepository.GetListAsync(next, userInfos, cancellationToken)); - } + userInfos.AddRange(nextUsers); + allUsers.AddRange(users); + } while (users.Any()); - userInfos.AddRange(nextUsers); - allUsers.AddRange(users); - } while (users.Any()); - - return allUsers; + return allUsers; + } } public virtual async Task LinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser, CancellationToken cancellationToken = default) { - if (sourceLinkUser.UserId == targetLinkUser.UserId && sourceLinkUser.TenantId == targetLinkUser.TenantId) + using (CurrentTenant.Change(null)) { - return; - } + if (sourceLinkUser.UserId == targetLinkUser.UserId && sourceLinkUser.TenantId == targetLinkUser.TenantId) + { + return; + } - if (await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken)) - { - return; - } + if (await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken)) + { + return; + } - using (CurrentTenant.Change(null)) - { var userLink = new IdentityLinkUser( GuidGenerator.Create(), sourceLinkUser, @@ -96,7 +98,7 @@ namespace Volo.Abp.Identity { if (includeIndirect) { - return (await IdentityLinkUserRepository.GetListAsync(sourceLinkUser, cancellationToken: cancellationToken)) + return (await GetListAsync(sourceLinkUser, true, cancellationToken: cancellationToken)) .Any(x => x.SourceTenantId == targetLinkUser.TenantId && x.SourceUserId == targetLinkUser.UserId || x.TargetTenantId == targetLinkUser.TenantId && x.TargetUserId == targetLinkUser.UserId); } @@ -106,13 +108,13 @@ namespace Volo.Abp.Identity public virtual async Task UnlinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser, CancellationToken cancellationToken = default) { - if (!await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken)) - { - return; - } - using (CurrentTenant.Change(null)) { + if (!await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken)) + { + return; + } + var linkedUser = await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser, cancellationToken); if (linkedUser != null) { From b17ad73719ad950a861ad4da451173a015717b26 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 6 Mar 2021 12:22:01 +0800 Subject: [PATCH 4/6] Use DataProtectorTokenProvider as LinkUserTokenProvider. --- .../AspNetCore/AbpIdentityAspNetCoreModule.cs | 1 + .../AspNetCore/LinkUserTokenProvider.cs | 19 +++++++++++++++++++ .../Identity/LinkUserTokenProviderConsts.cs | 9 +++++++++ .../AbpIdentityServiceCollectionExtensions.cs | 3 +-- .../Abp/Identity/IdentityUserLinkManager.cs | 13 ++++++++----- .../Abp/Identity/LinkUserTokenProvider.cs | 17 ----------------- .../AspNetCore/LinkUserTokenProvider_Tests.cs | 2 +- 7 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/LinkUserTokenProviderConsts.cs delete mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/LinkUserTokenProvider.cs diff --git a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs index 019ef0469e..82679b10b7 100644 --- a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs @@ -15,6 +15,7 @@ namespace Volo.Abp.Identity.AspNetCore { builder .AddDefaultTokenProviders() + .AddTokenProvider(LinkUserTokenProviderConsts.LinkUserTokenProviderName) .AddSignInManager(); }); } diff --git a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider.cs b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider.cs new file mode 100644 index 0000000000..2fadb53a83 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Volo.Abp.Identity.AspNetCore +{ + public class LinkUserTokenProvider : DataProtectorTokenProvider + { + public LinkUserTokenProvider( + IDataProtectionProvider dataProtectionProvider, + IOptions options, + ILogger> logger) + : base(dataProtectionProvider, options, logger) + { + + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/LinkUserTokenProviderConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/LinkUserTokenProviderConsts.cs new file mode 100644 index 0000000000..044f034e46 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/LinkUserTokenProviderConsts.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.Identity +{ + public static class LinkUserTokenProviderConsts + { + public static string LinkUserTokenProviderName { get; set; } = "AbpLinkUser"; + + public static string LinkUserTokenPurpose { get; set; } = "AbpLinkUserLogin"; + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs index c37889a897..5dfdf2944d 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs @@ -33,8 +33,7 @@ namespace Microsoft.Extensions.DependencyInjection return services .AddIdentityCore(setupAction) .AddRoles() - .AddClaimsPrincipalFactory() - .AddTokenProvider(LinkUserTokenProvider.LinkUserTokenProviderName); + .AddClaimsPrincipalFactory(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs index d4c89a6ad5..9320a2e572 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Text.Encodings.Web; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Services; @@ -128,10 +129,12 @@ namespace Volo.Abp.Identity using (CurrentTenant.Change(targetLinkUser.TenantId)) { var user = await UserManager.GetByIdAsync(targetLinkUser.UserId); - return await UserManager.GenerateUserTokenAsync( + var token = await UserManager.GenerateUserTokenAsync( user, - LinkUserTokenProvider.LinkUserTokenProviderName, - LinkUserTokenProvider.LinkUserTokenPurpose); + LinkUserTokenProviderConsts.LinkUserTokenProviderName, + LinkUserTokenProviderConsts.LinkUserTokenPurpose); + + return UrlEncoder.Default.Encode(token); } } @@ -142,8 +145,8 @@ namespace Volo.Abp.Identity var user = await UserManager.GetByIdAsync(targetLinkUser.UserId); return await UserManager.VerifyUserTokenAsync( user, - LinkUserTokenProvider.LinkUserTokenProviderName, - LinkUserTokenProvider.LinkUserTokenPurpose, + LinkUserTokenProviderConsts.LinkUserTokenProviderName, + LinkUserTokenProviderConsts.LinkUserTokenPurpose, token); } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/LinkUserTokenProvider.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/LinkUserTokenProvider.cs deleted file mode 100644 index 706c045578..0000000000 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/LinkUserTokenProvider.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; - -namespace Volo.Abp.Identity -{ - public class LinkUserTokenProvider : TotpSecurityStampBasedTokenProvider - { - public const string LinkUserTokenProviderName = "AbpLinkUser"; - - public const string LinkUserTokenPurpose = "AbpLinkUserLogin"; - - public override Task CanGenerateTwoFactorTokenAsync(UserManager manager, IdentityUser user) - { - return Task.FromResult(false); - } - } -} diff --git a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs index 2791de9a4f..fe87b67d72 100644 --- a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs @@ -13,7 +13,7 @@ namespace Volo.Abp.Identity.AspNetCore var identityOptions = GetRequiredService>().Value; identityOptions.Tokens.ProviderMap.ShouldContain(x => - x.Key == LinkUserTokenProvider.LinkUserTokenProviderName && + x.Key == LinkUserTokenProviderConsts.LinkUserTokenProviderName && x.Value.ProviderType == typeof(LinkUserTokenProvider)); } } From c85dd1df0b0e78515a61de2ab2414d4a4d093ef9 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 6 Mar 2021 14:25:42 +0800 Subject: [PATCH 5/6] Fix GenerateAndVerifyLinkTokenAsync test. --- .../AspNetCore/LinkUserTokenProvider_Tests.cs | 26 ++++++++++++++++++- .../Identity/IdentityLinkUserManager_Tests.cs | 11 -------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs index fe87b67d72..8e85a1125f 100644 --- a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/LinkUserTokenProvider_Tests.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Identity; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Shouldly; using Xunit; @@ -7,6 +8,19 @@ namespace Volo.Abp.Identity.AspNetCore { public class LinkUserTokenProvider_Tests : AbpIdentityAspNetCoreTestBase { + protected IIdentityUserRepository UserRepository { get; } + protected IIdentityLinkUserRepository IdentityLinkUserRepository { get; } + protected IdentityLinkUserManager IdentityLinkUserManager { get; } + protected IdentityTestData TestData { get; } + + public LinkUserTokenProvider_Tests() + { + UserRepository = GetRequiredService(); + IdentityLinkUserRepository = GetRequiredService(); + IdentityLinkUserManager = GetRequiredService(); + TestData = GetRequiredService(); + } + [Fact] public void LinkUserTokenProvider_Should_Be_Register() { @@ -16,5 +30,15 @@ namespace Volo.Abp.Identity.AspNetCore x.Key == LinkUserTokenProviderConsts.LinkUserTokenProviderName && x.Value.ProviderType == typeof(LinkUserTokenProvider)); } + + [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(); + } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs index 4bb77cad67..953824ef5b 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityLinkUserManager_Tests.cs @@ -188,16 +188,5 @@ namespace Volo.Abp.Identity (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(); - } - } } From 24765db85ddce06bf057001f16b5f1aa37b8dd92 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 6 Mar 2021 14:58:19 +0800 Subject: [PATCH 6/6] Cancel the token encoding --- .../Volo/Abp/Identity/IdentityUserLinkManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs index 9320a2e572..39b41247e4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs @@ -129,12 +129,10 @@ namespace Volo.Abp.Identity using (CurrentTenant.Change(targetLinkUser.TenantId)) { var user = await UserManager.GetByIdAsync(targetLinkUser.UserId); - var token = await UserManager.GenerateUserTokenAsync( + return await UserManager.GenerateUserTokenAsync( user, LinkUserTokenProviderConsts.LinkUserTokenProviderName, LinkUserTokenProviderConsts.LinkUserTokenPurpose); - - return UrlEncoder.Default.Encode(token); } }