diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs index b8d5679aff..d23954e11d 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs @@ -44,6 +44,12 @@ public interface IIdentityUserRepository : IBasicRepository CancellationToken cancellationToken = default ); + Task RemoveClaimFromAllUsers( + string claimType, + bool autoSave = false, + CancellationToken cancellationToken = default + ); + Task> GetListByNormalizedRoleNameAsync( string normalizedRoleName, bool includeDetails = false, diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs index d7a13c8476..19b18ec56d 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.Domain.Services; namespace Volo.Abp.Identity; @@ -6,10 +8,12 @@ namespace Volo.Abp.Identity; public class IdentityClaimTypeManager : DomainService { protected IIdentityClaimTypeRepository IdentityClaimTypeRepository { get; } + protected IIdentityUserRepository IdentityUserRepository { get; } - public IdentityClaimTypeManager(IIdentityClaimTypeRepository identityClaimTypeRepository) + public IdentityClaimTypeManager(IIdentityClaimTypeRepository identityClaimTypeRepository, IIdentityUserRepository identityUserRepository) { IdentityClaimTypeRepository = identityClaimTypeRepository; + IdentityUserRepository = identityUserRepository; } public virtual async Task CreateAsync(IdentityClaimType claimType) @@ -37,4 +41,17 @@ public class IdentityClaimTypeManager : DomainService return await IdentityClaimTypeRepository.UpdateAsync(claimType); } + + public virtual async Task DeleteAsync(Guid id) + { + var claimType = await IdentityClaimTypeRepository.GetAsync(id); + if (claimType.IsStatic) + { + throw new AbpException($"Can not delete a static ClaimType."); + } + + //Remove claim of this type from all users + await IdentityUserRepository.RemoveClaimFromAllUsers(claimType.Name); + await IdentityClaimTypeRepository.DeleteAsync(id); + } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index 2b261b065e..ca6988d72b 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -74,7 +74,7 @@ public class EfCoreIdentityUserRepository : EfCoreRepository x.Name).ToArray() }).ToListAsync(cancellationToken: cancellationToken); - + var orgUnitRoles = await (from userOu in dbContext.Set() join roleOu in dbContext.Set() on userOu.OrganizationUnitId equals roleOu.OrganizationUnitId join role in dbContext.Roles on roleOu.RoleId equals role.Id @@ -89,7 +89,7 @@ public class EfCoreIdentityUserRepository : EfCoreRepository x.Name).ToArray() }).ToListAsync(cancellationToken: cancellationToken); - + return userRoles.Concat(orgUnitRoles).GroupBy(x => x.Id).Select(x => new IdentityUserIdWithRoleNames {Id = x.Key, RoleNames = x.SelectMany(y => y.RoleNames).Distinct().ToArray()}).ToList(); } @@ -145,6 +145,21 @@ public class EfCoreIdentityUserRepository : EfCoreRepository().Where(uc => uc.ClaimType == claimType).ToListAsync(cancellationToken: cancellationToken); + if (userClaims.Any()) + { + (await GetDbContextAsync()).Set().RemoveRange(userClaims); + } + + if (autoSave) + { + await dbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + } + } + public virtual async Task> GetListByNormalizedRoleNameAsync( string normalizedRoleName, bool includeDetails = false, @@ -216,7 +231,7 @@ public class EfCoreIdentityUserRepository : EfCoreRepository().Where(q => q.RoleId == roleId.Value).Select(q => q.OrganizationUnitId).ToArrayAsync(cancellationToken: cancellationToken); query = query.Where(identityUser => identityUser.Roles.Any(x => x.RoleId == roleId.Value) || identityUser.OrganizationUnits.Any(x => organizationUnitIds.Contains(x.OrganizationUnitId))); } - + return query .WhereIf( !filter.IsNullOrWhiteSpace(), diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs index 1ce97c4dfd..2f4560fef9 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs @@ -108,6 +108,20 @@ public class MongoIdentityUserRepository : MongoDbRepository u.Claims.Any(c => c.ClaimType == claimType)) + .ToListAsync(GetCancellationToken(cancellationToken)); + + foreach (var user in users) + { + user.Claims.RemoveAll(c => c.ClaimType == claimType); + } + + await UpdateManyAsync(users, cancellationToken: cancellationToken); + } + public virtual async Task> GetListByNormalizedRoleNameAsync( string normalizedRoleName, bool includeDetails = false, @@ -164,7 +178,7 @@ public class MongoIdentityUserRepository : MongoDbRepository>() @@ -365,17 +379,17 @@ public class MongoIdentityUserRepository : MongoDbRepository u.Roles) .Select(userRole => new { userRole.UserId, userRole.RoleId }) .GroupBy(x => x.UserId).ToDictionary(x => x.Key, x => x.Select(r => r.RoleId).ToList()); var userAndOrganizationUnitIds = users.SelectMany(u => u.OrganizationUnits) .Select(userOrganizationUnit => new { userOrganizationUnit.UserId, userOrganizationUnit.OrganizationUnitId }) .GroupBy(x => x.UserId).ToDictionary(x => x.Key, x => x.Select(r => r.OrganizationUnitId).ToList()); - + var organizationUnitIds = userAndOrganizationUnitIds.SelectMany(x => x.Value); var roleIds = userAndRoleIds.SelectMany(x => x.Value); - + var organizationUnitAndRoleIds = await (await GetMongoQueryableAsync(cancellationToken)).Where(ou => organizationUnitIds.Contains(ou.Id)) .Select(userOrganizationUnit => new { @@ -384,10 +398,10 @@ public class MongoIdentityUserRepository : MongoDbRepository x.Roles.Select(r => r.RoleId)).ToList(); var allRoleIds = roleIds.Union(allOrganizationUnitRoleIds); - + var roles = await (await GetMongoQueryableAsync(cancellationToken)).Where(r => allRoleIds.Contains(r.Id)).Select(r => new{ r.Id, r.Name }).ToListAsync(cancellationToken); var userRoles = userAndRoleIds.ToDictionary(x => x.Key, x => roles.Where(r => x.Value.Contains(r.Id)).Select(r => r.Name).ToArray()); - + var result = userRoles.Select(x => new IdentityUserIdWithRoleNames { Id = x.Key, RoleNames = x.Value }).ToList(); foreach (var userAndOrganizationUnitId in userAndOrganizationUnitIds) @@ -429,17 +443,17 @@ public class MongoIdentityUserRepository : MongoDbRepository(cancellationToken)) .Where(ou => ou.Roles.Any(r => r.RoleId == roleId.Value)) .Select(userOrganizationUnit => userOrganizationUnit.Id) .ToArray(); - + query = query.Where(identityUser => identityUser.Roles.Any(x => x.RoleId == roleId.Value) || identityUser.OrganizationUnits.Any(x => organizationUnitIds.Contains(x.OrganizationUnitId))); } - + return query .WhereIf>( !filter.IsNullOrWhiteSpace(), diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs index 9a86f4964b..6028a07520 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Guids; using Volo.Abp.Modularity; +using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.Identity; @@ -16,11 +18,19 @@ public abstract class IdentityClaimTypeRepository_Tests : AbpIde { protected IIdentityClaimTypeRepository ClaimTypeRepository { get; } protected IGuidGenerator GuidGenerator { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + protected IIdentityUserRepository UserRepository { get; } + protected IdentityUserManager IdentityUserManager { get; } + protected IdentityTestData IdentityTestData { get; } public IdentityClaimTypeRepository_Tests() { ClaimTypeRepository = ServiceProvider.GetRequiredService(); GuidGenerator = ServiceProvider.GetRequiredService(); + UnitOfWorkManager = ServiceProvider.GetRequiredService(); + IdentityUserManager = ServiceProvider.GetRequiredService(); + UserRepository = ServiceProvider.GetRequiredService(); + IdentityTestData = ServiceProvider.GetRequiredService(); } [Fact] @@ -42,7 +52,7 @@ public abstract class IdentityClaimTypeRepository_Tests : AbpIde { (await ClaimTypeRepository.GetCountAsync("Age")).ShouldBe(1); } - + [Fact] public async Task GetListAsyncByNames() { @@ -50,4 +60,38 @@ public abstract class IdentityClaimTypeRepository_Tests : AbpIde result.Count.ShouldBe(2); } + + [Fact] + public async Task DeleteAsync() + { + var ageClaim = await ClaimTypeRepository.FindAsync(IdentityTestData.AgeClaimId); + ageClaim.ShouldNotBeNull(); + + using (var uow = UnitOfWorkManager.Begin()) + { + var john = await UserRepository.FindAsync(IdentityTestData.UserJohnId); + john.ShouldNotBeNull(); + await IdentityUserManager.AddClaimAsync(john, new Claim(ageClaim.Name, "18")); + + var userClaims = await IdentityUserManager.GetClaimsAsync(john); + userClaims.ShouldContain(c => c.Type == ageClaim.Name && c.Value == "18"); + + await uow.CompleteAsync(); + } + + await ClaimTypeRepository.DeleteAsync(ageClaim.Id); + await UserRepository.RemoveClaimFromAllUsers(ageClaim.Name); + + using (var uow = UnitOfWorkManager.Begin()) + { + var john = await UserRepository.FindAsync(IdentityTestData.UserJohnId); + john.ShouldNotBeNull(); + + var userClaims = await IdentityUserManager.GetClaimsAsync(john); + + userClaims.ShouldNotContain(c => c.Type == ageClaim.Name && c.Value == "18"); + + await uow.CompleteAsync(); + } + } }