Merge pull request #7953 from abpframework/maliming/Linked-user-enhancements

Link users enhancements.
pull/7719/head^2
İsmail ÇAĞDAŞ 5 years ago committed by GitHub
commit 1c1544c5d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -15,6 +15,7 @@ namespace Volo.Abp.Identity.AspNetCore
{
builder
.AddDefaultTokenProviders()
.AddTokenProvider<LinkUserTokenProvider>(LinkUserTokenProviderConsts.LinkUserTokenProviderName)
.AddSignInManager<AbpSignInManager>();
});
}

@ -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<IdentityUser>
{
public LinkUserTokenProvider(
IDataProtectionProvider dataProtectionProvider,
IOptions<DataProtectionTokenProviderOptions> options,
ILogger<DataProtectorTokenProvider<IdentityUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
}

@ -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";
}
}

@ -33,8 +33,7 @@ namespace Microsoft.Extensions.DependencyInjection
return services
.AddIdentityCore<IdentityUser>(setupAction)
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<AbpUserClaimsPrincipalFactory>()
.AddTokenProvider<LinkUserTokenProvider>(LinkUserTokenProvider.LinkUserTokenProviderName);
.AddClaimsPrincipalFactory<AbpUserClaimsPrincipalFactory>();
}
}
}

@ -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<List<IdentityLinkUser>> GetListAsync(
IdentityLinkUserInfo linkUserInfo,
List<IdentityLinkUserInfo> excludes = null,
CancellationToken cancellationToken = default);
Task DeleteAsync(
IdentityLinkUserInfo linkUserInfo,
CancellationToken cancellationToken = default);
}

@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Abp.MultiTenancy;
@ -20,74 +23,128 @@ namespace Volo.Abp.Identity
CurrentTenant = currentTenant;
}
public virtual async Task LinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser)
public async Task<List<IdentityLinkUser>> GetListAsync(IdentityLinkUserInfo linkUserInfo, bool includeIndirect = false, CancellationToken cancellationToken = default)
{
if (sourceLinkUser.UserId == targetLinkUser.UserId && sourceLinkUser.TenantId == targetLinkUser.TenantId)
using (CurrentTenant.Change(null))
{
return;
}
var users = await IdentityLinkUserRepository.GetListAsync(linkUserInfo, cancellationToken: cancellationToken);
if (includeIndirect == false)
{
return users;
}
if (await IsLinkedAsync(sourceLinkUser, targetLinkUser))
{
return;
var userInfos = new List<IdentityLinkUserInfo>()
{
linkUserInfo
};
var allUsers = new List<IdentityLinkUser>();
allUsers.AddRange(users);
do
{
var nextUsers = new List<IdentityLinkUserInfo>();
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<IdentityLinkUser>();
foreach (var next in nextUsers)
{
users.AddRange(await IdentityLinkUserRepository.GetListAsync(next, userInfos, cancellationToken));
}
userInfos.AddRange(nextUsers);
allUsers.AddRange(users);
} while (users.Any());
return allUsers;
}
}
public virtual async Task LinkAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser, CancellationToken cancellationToken = default)
{
using (CurrentTenant.Change(null))
{
if (sourceLinkUser.UserId == targetLinkUser.UserId && sourceLinkUser.TenantId == targetLinkUser.TenantId)
{
return;
}
if (await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken))
{
return;
}
var userLink = new IdentityLinkUser(
GuidGenerator.Create(),
sourceLinkUser,
targetLinkUser);
await IdentityLinkUserRepository.InsertAsync(userLink, true);
await IdentityLinkUserRepository.InsertAsync(userLink, true, cancellationToken);
}
}
public virtual async Task<bool> IsLinkedAsync(IdentityLinkUserInfo sourceLinkUser, IdentityLinkUserInfo targetLinkUser)
public virtual async Task<bool> 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 GetListAsync(sourceLinkUser, true, 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))
{
return;
}
using (CurrentTenant.Change(null))
{
var linkedUser = await IdentityLinkUserRepository.FindAsync(sourceLinkUser, targetLinkUser);
if (!await IsLinkedAsync(sourceLinkUser, targetLinkUser, cancellationToken: cancellationToken))
{
return;
}
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<string> GenerateLinkTokenAsync(IdentityLinkUserInfo targetLinkUser)
public virtual async Task<string> GenerateLinkTokenAsync(IdentityLinkUserInfo targetLinkUser, CancellationToken cancellationToken = default)
{
using (CurrentTenant.Change(targetLinkUser.TenantId))
{
var user = await UserManager.GetByIdAsync(targetLinkUser.UserId);
return await UserManager.GenerateUserTokenAsync(
user,
LinkUserTokenProvider.LinkUserTokenProviderName,
LinkUserTokenProvider.LinkUserTokenPurpose);
LinkUserTokenProviderConsts.LinkUserTokenProviderName,
LinkUserTokenProviderConsts.LinkUserTokenPurpose);
}
}
public virtual async Task<bool> VerifyLinkTokenAsync(IdentityLinkUserInfo targetLinkUser, string token)
public virtual async Task<bool> VerifyLinkTokenAsync(IdentityLinkUserInfo targetLinkUser, string token, CancellationToken cancellationToken = default)
{
using (CurrentTenant.Change(targetLinkUser.TenantId))
{
var user = await UserManager.GetByIdAsync(targetLinkUser.UserId);
return await UserManager.VerifyUserTokenAsync(
user,
LinkUserTokenProvider.LinkUserTokenProviderName,
LinkUserTokenProvider.LinkUserTokenPurpose,
LinkUserTokenProviderConsts.LinkUserTokenProviderName,
LinkUserTokenProviderConsts.LinkUserTokenPurpose,
token);
}
}

@ -1,17 +0,0 @@
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);
}
}
}

@ -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<List<IdentityLinkUser>> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default)
public virtual async Task<List<IdentityLinkUser>> GetListAsync(IdentityLinkUserInfo linkUserInfo, List<IdentityLinkUserInfo> excludes = null,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
IQueryable<IdentityLinkUser> 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);
}
}
}

@ -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<List<IdentityLinkUser>> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default)
public virtual async Task<List<IdentityLinkUser>> GetListAsync(IdentityLinkUserInfo linkUserInfo, List<IdentityLinkUserInfo> 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);
}
}
}

@ -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,14 +8,37 @@ 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<IIdentityUserRepository>();
IdentityLinkUserRepository = GetRequiredService<IIdentityLinkUserRepository>();
IdentityLinkUserManager = GetRequiredService<IdentityLinkUserManager>();
TestData = GetRequiredService<IdentityTestData>();
}
[Fact]
public void LinkUserTokenProvider_Should_Be_Register()
{
var identityOptions = GetRequiredService<IOptions<IdentityOptions>>().Value;
identityOptions.Tokens.ProviderMap.ShouldContain(x =>
x.Key == LinkUserTokenProvider.LinkUserTokenProviderName &&
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();
}
}
}

@ -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<IdentityTestData>();
}
[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()
{
@ -71,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();
}
}
}

@ -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();
}
}
}

Loading…
Cancel
Save