Skip to content

Commit

Permalink
perf: optimize account delegation login
Browse files Browse the repository at this point in the history
2. account link
3. account delegation
  • Loading branch information
jxnkwlp committed Nov 17, 2023
1 parent 0ba9148 commit b76e633
Show file tree
Hide file tree
Showing 21 changed files with 397 additions and 42 deletions.
13 changes: 11 additions & 2 deletions modules/account/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# Account
# Account

Account enhancements, such as 2fa, external login, account settings.
an abp module that provider account service, such as login, 2fa, account link, impersonation, settings

- Local Login
- Externa Login
- MFA Login
- 2FA Management
- Account Link
- Account User Impersonation
- Account User Delegation
- Account Security Logs
4 changes: 2 additions & 2 deletions modules/account/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

<PropertyGroup>
<Product>Passingwind.Abp.Account</Product>
<Description>an abp module that provider account service, such as login, 2fa, account settings. </Description>
<Description>an abp module that provider account service, such as login, 2fa, account link, impersonation, settings. </Description>
<PackageTags>abp-module</PackageTags>
<Version>0.2.0</Version>
<PackageVersion>0.2.9</PackageVersion>
<PackageVersion>0.2.10</PackageVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Passingwind.Abp.Identity;

public class AccountLinkTokenValidationRequestDto
{
[Required]
public Guid UserId { get; set; }
[Required]
public string Token { get; set; } = null!;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.ComponentModel.DataAnnotations;

namespace Passingwind.Abp.Identity;

public class AccountUnlinkDto
{
[Required]
public Guid UserId { get; set; }
public Guid TenantId { get; set; }
public Guid? TenantId { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace Passingwind.Abp.Account;

public class AccountUserDelegationCreateDto
{
public Guid UserId { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace Passingwind.Abp.Account;

public class AccountUserDelegationDto
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public string? UserName { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public bool IsActive { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ namespace Passingwind.Abp.Account;

public interface IAccountImpersonationAppService : IApplicationService
{
/// <summary>
/// Logout current user and return to impersonator user
/// </summary>
Task LogoutAsync();

/// <summary>
/// Login to specified user with id
/// </summary>
/// <param name="userId"></param>
Task LoginAsync(Guid userId);

/// <summary>
/// Link login to specified user with id
/// </summary>
/// <param name="userId"></param>
Task LinkLoginAsync(Guid userId);

/// <summary>
/// delegation login
/// </summary>
/// <param name="userId"></param>
Task DelegationLoginAsync(Guid userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;

namespace Passingwind.Abp.Account;

public interface IAccountUserDelegationAppService : IApplicationService
{
Task<ListResultDto<AccountUserDelegationDto>> GetMyDelegationListAsync();

Task<ListResultDto<AccountUserDelegationDto>> GetDelegatedListAsync();

Task CreateAsync(AccountUserDelegationCreateDto input);

Task DeleteAsync(Guid id);

Task<ListResultDto<UserBasicDto>> UserLookupAsync(string? filter = null);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using Volo.Abp.Application.Dtos;

namespace Passingwind.Abp.Account;

public class UserBasicDto : EntityDto<Guid>
{
public string UserName { get; set; } = null!;
public string? Name { get; set; }
public string? SurName { get; set; }
public string? Email { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ public AccountApplicationAutoMapperProfile()
CreateMap<AccountCaptchaSettings, AccountCaptchaSettingsDto>().ReverseMap();
CreateMap<AccountRecaptchaSettings, AccountRecaptchaSettingsDto>().ReverseMap();
CreateMap<AccountExternalLoginSettings, AccountExternalLoginSettingsDto>().ReverseMap();
CreateMap<IdentityUser, UserBasicDto>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Volo.Abp.AutoMapper;
using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;

namespace Passingwind.Abp.Account;

Expand All @@ -17,6 +18,7 @@ namespace Passingwind.Abp.Account;
typeof(AbpAccountApplicationModule),
typeof(AbpIdentityAspNetCoreModule),
typeof(AbpDddApplicationModule),
typeof(AbpMultiTenancyAbstractionsModule),
typeof(AbpAutoMapperModule)
)]
public class AccountApplicationModule : AbpModule
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
Expand All @@ -26,20 +27,47 @@ public class AccountImpersonationAppService : AccountAppBaseService, IAccountImp
protected IdentityUserManager UserManager { get; }
protected IdentitySecurityLogManager SecurityLogManager { get; }
protected IdentityLinkUserManager LinkUserManager { get; }
protected IdentityUserDelegationManager UserDelegationManager { get; }
protected IOptions<IdentityOptions> IdentityOptions { get; }

public AccountImpersonationAppService(
SignInManager signInManager,
IdentityUserManager userManager,
IdentitySecurityLogManager securityLogManager,
IdentityLinkUserManager linkUserManager,
IOptions<IdentityOptions> identityOptions)
IOptions<IdentityOptions> identityOptions,
IdentityUserDelegationManager userDelegationManager)
{
SignInManager = signInManager;
UserManager = userManager;
SecurityLogManager = securityLogManager;
LinkUserManager = linkUserManager;
IdentityOptions = identityOptions;
UserDelegationManager = userDelegationManager;
}

public virtual async Task LogoutAsync()
{
await IdentityOptions.SetAsync();

var userId = CurrentUser.FindImpersonatorUserId();
var tenantId = CurrentUser.FindImpersonatorTenantId();

if (!userId.HasValue)
{
throw new AbpAuthorizationException();
}

if (tenantId.HasValue)
{
CurrentTenant.Change(tenantId.Value);
}

await IdentityOptions.SetAsync();

var user = await UserManager.FindByIdAsync(userId.Value.ToString());

await SignInManager.SignInAsync(user!, false);
}

[Authorize(IdentityPermissionNamesV2.Users.Impersonation)]
Expand All @@ -63,19 +91,24 @@ public virtual async Task LinkLoginAsync(Guid userId)

var user = await UserManager.GetByIdAsync(userId);

var source = new IdentityLinkUserInfo(CurrentUser.Id!.Value, CurrentUser.TenantId);
var source = new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentUser.TenantId);
var target = new IdentityLinkUserInfo(userId, user.TenantId);

if (user.TenantId.HasValue && user.TenantId != CurrentUser.TenantId)
{
CurrentTenant.Change(user.TenantId.Value);
}

if (await LinkUserManager.IsLinkedAsync(source, target, true))
{
await SignInManager.SignInWithClaimsAsync(user, false, new Claim[0]);
await ImpersonateLoginAsync(user);

Logger.LogInformation("User with id '{0}' has been link login by user id '{1}'", user.Id, source.UserId);

await SecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = "ImpersonationLogin",
Action = "LinkLogin",
UserName = user.UserName,
ExtraProperties = { { "SourceUserId", source.UserId } }
});
Expand All @@ -86,6 +119,30 @@ await SecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
}
}

public virtual async Task DelegationLoginAsync(Guid userId)
{
var delegations = await UserDelegationManager.GetActiveDelegationsAsync(CurrentUser.GetId());

if (!delegations.Any(x => x.SourceUserId == userId))
{
throw new BusinessException(AccountErrorCodes.UserNotDelegated);
}

var user = await UserManager.GetByIdAsync(userId);

await ImpersonateLoginAsync(user);

Logger.LogInformation("User with id '{0}' has been delegation login by user id '{1}'", user.Id, CurrentUser.GetId());

await SecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = "DelegationLogin",
UserName = user.UserName,
ExtraProperties = { { "SourceUserId", CurrentUser.GetId() } }
});
}

protected virtual async Task ImpersonateLoginAsync(IdentityUser user)
{
IList<Claim> cliams = new List<Claim>() {
Expand Down
Loading

0 comments on commit b76e633

Please sign in to comment.