diff --git a/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleCreationJob.cs b/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleCreationJob.cs new file mode 100644 index 00000000..096b0c61 --- /dev/null +++ b/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleCreationJob.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using EShopOnAbp.IdentityService.Keycloak; +using Microsoft.Extensions.Logging; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; + +namespace EShopOnAbp.IdentityService.BackgroundJobs.Roles; + +public class KeycloakRoleCreationJob : AsyncBackgroundJob, ITransientDependency +{ + private readonly KeycloakService _keycloakService; + private readonly ILogger _logger; + + public KeycloakRoleCreationJob(KeycloakService keycloakService, ILogger logger) + { + _keycloakService = keycloakService; + _logger = logger; + } + + public override async Task ExecuteAsync(IdentityRoleCreationArgs args) + { + try + { + var existingRole = (await _keycloakService.GetRolesAsync()).FirstOrDefault(q => q.Name == args.Name); + if (existingRole != null) + { + return; + } + + await _keycloakService.CreateRoleAsync(args.Name); + } + catch (Exception e) + { + _logger.LogWarning($"Keycloak role creation with the name:{args.Name} failed!"); + throw; + } + } +} + +public record IdentityRoleCreationArgs(string Name); \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleDeletionJob.cs b/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleDeletionJob.cs new file mode 100644 index 00000000..812bf290 --- /dev/null +++ b/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleDeletionJob.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using EShopOnAbp.IdentityService.Keycloak; +using Microsoft.Extensions.Logging; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; + +namespace EShopOnAbp.IdentityService.BackgroundJobs.Roles; + +public class KeycloakRoleDeletionJob : AsyncBackgroundJob, ITransientDependency +{ + private readonly KeycloakService _keycloakService; + private readonly ILogger _logger; + + public KeycloakRoleDeletionJob(KeycloakService keycloakService, ILogger logger) + { + _keycloakService = keycloakService; + _logger = logger; + } + + public override async Task ExecuteAsync(IdentityRoleDeletionArgs args) + { + try + { + var existingRole = (await _keycloakService.GetRolesAsync()).FirstOrDefault(q => q.Name == args.Name); + if (existingRole == null) + { + return; + } + + await _keycloakService.DeleteRoleByIdAsync(existingRole.Id); + } + catch (Exception e) + { + _logger.LogWarning($"Could not delete the role with the name:{args.Name} from Keycloak server!"); + throw; + } + } +} + +public record IdentityRoleDeletionArgs(string Name); \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleUpdatingJob.cs b/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleUpdatingJob.cs new file mode 100644 index 00000000..b7d0f95c --- /dev/null +++ b/services/identity/src/EShopOnAbp.IdentityService.Application/BackgroundJobs/Roles/KeycloakRoleUpdatingJob.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using EShopOnAbp.IdentityService.Keycloak; +using Microsoft.Extensions.Logging; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; + +namespace EShopOnAbp.IdentityService.BackgroundJobs.Roles; + +public class KeycloakRoleUpdatingJob : AsyncBackgroundJob, ITransientDependency +{ + private readonly KeycloakService _keycloakService; + private readonly ILogger _logger; + + public KeycloakRoleUpdatingJob(KeycloakService keycloakService, ILogger logger) + { + _keycloakService = keycloakService; + _logger = logger; + } + + public override async Task ExecuteAsync(IdentityRoleUpdatingArgs args) + { + try + { + var existingRole = (await _keycloakService.GetRolesAsync()).FirstOrDefault(q => q.Name == args.Name); + if (existingRole == null) + { + _logger.LogWarning($"Role with the name:{args.Name} couldn't be found to update!"); + return; + } + + existingRole.Name = args.Name; + + await _keycloakService.UpdateRoleAsync(existingRole.Id, existingRole); + } + catch (Exception e) + { + _logger.LogWarning($"Could not delete the role with the name:{args.Name} from Keycloak server!"); + throw; + } + } +} + +public record IdentityRoleUpdatingArgs(string Name); \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.Application/Identity/EShopIdentityRoleAppService.cs b/services/identity/src/EShopOnAbp.IdentityService.Application/Identity/EShopIdentityRoleAppService.cs new file mode 100644 index 00000000..20d7c5e1 --- /dev/null +++ b/services/identity/src/EShopOnAbp.IdentityService.Application/Identity/EShopIdentityRoleAppService.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading.Tasks; +using EShopOnAbp.IdentityService.BackgroundJobs.Roles; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; + +namespace EShopOnAbp.IdentityService.Identity; + +[ExposeServices(typeof(IdentityRoleAppService), typeof(IIdentityRoleAppService))] +public class EShopIdentityRoleAppService : IdentityRoleAppService +{ + private readonly IBackgroundJobManager _backgroundJobManager; + private readonly IdentityRoleManager _identityRoleManager; + + public EShopIdentityRoleAppService(IdentityRoleManager roleManager, IIdentityRoleRepository roleRepository, + IBackgroundJobManager backgroundJobManager, IdentityRoleManager identityRoleManager) : base( + roleManager, roleRepository) + { + _backgroundJobManager = backgroundJobManager; + _identityRoleManager = identityRoleManager; + } + + public override async Task CreateAsync(IdentityRoleCreateDto input) + { + var result = await base.CreateAsync(input); + await _backgroundJobManager.EnqueueAsync(new IdentityRoleCreationArgs(result.Name)); + + return result; + } + + public override async Task UpdateAsync(Guid id, IdentityRoleUpdateDto input) + { + var result = await base.UpdateAsync(id, input); + await _backgroundJobManager.EnqueueAsync(new IdentityRoleUpdatingArgs(result.Name)); + + return result; + } + + public override async Task DeleteAsync(Guid id) + { + var existingRole = await _identityRoleManager.FindByIdAsync(id.ToString()); + await base.DeleteAsync(id); + if (existingRole == null) + { + return; + } + + await _backgroundJobManager.EnqueueAsync(new IdentityRoleDeletionArgs(existingRole.Name)); + } +} \ No newline at end of file diff --git a/services/identity/src/EShopOnAbp.IdentityService.Application/EShopIdentityUserAppService.cs b/services/identity/src/EShopOnAbp.IdentityService.Application/Identity/EShopIdentityUserAppService.cs similarity index 95% rename from services/identity/src/EShopOnAbp.IdentityService.Application/EShopIdentityUserAppService.cs rename to services/identity/src/EShopOnAbp.IdentityService.Application/Identity/EShopIdentityUserAppService.cs index 39ac34cc..8a370a23 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.Application/EShopIdentityUserAppService.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.Application/Identity/EShopIdentityUserAppService.cs @@ -1,13 +1,13 @@ using System; using System.Threading.Tasks; -using EShopOnAbp.IdentityService.BackgroundJobs.User; +using EShopOnAbp.IdentityService.BackgroundJobs.Users; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Volo.Abp.BackgroundJobs; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; -namespace EShopOnAbp.IdentityService; +namespace EShopOnAbp.IdentityService.Identity; [ExposeServices(typeof(IdentityUserAppService), typeof(IIdentityUserAppService))] public class EShopIdentityUserAppService : IdentityUserAppService diff --git a/services/identity/src/EShopOnAbp.IdentityService.Application/Keycloak/KeycloakService.cs b/services/identity/src/EShopOnAbp.IdentityService.Application/Keycloak/KeycloakService.cs index 19da1314..175d5d7d 100644 --- a/services/identity/src/EShopOnAbp.IdentityService.Application/Keycloak/KeycloakService.cs +++ b/services/identity/src/EShopOnAbp.IdentityService.Application/Keycloak/KeycloakService.cs @@ -63,4 +63,23 @@ public class KeycloakService : ITransientDependency return _keycloakClient.AddRealmRoleMappingsToUserAsync(_keycloakOptions.RealmName, userId, roles, cancellationToken); } + + public Task CreateRoleAsync(string name, CancellationToken cancellationToken = default) + { + Role role = new Role + { + Name = name + }; + return _keycloakClient.CreateRoleAsync(_keycloakOptions.RealmName, role, cancellationToken); + } + + public Task DeleteRoleByIdAsync(string id, CancellationToken cancellationToken = default) + { + return _keycloakClient.DeleteRoleByIdAsync(_keycloakOptions.RealmName, id, cancellationToken); + } + + public Task UpdateRoleAsync(string id, Role role, CancellationToken cancellationToken = default) + { + return _keycloakClient.UpdateRoleByIdAsync(_keycloakOptions.RealmName, id, role, cancellationToken); + } } \ No newline at end of file diff --git a/shared/EShopOnAbp.Keycloak.DbMigrator/KeycloakDataSeeder.cs b/shared/EShopOnAbp.Keycloak.DbMigrator/KeycloakDataSeeder.cs index 73259647..3f297757 100644 --- a/shared/EShopOnAbp.Keycloak.DbMigrator/KeycloakDataSeeder.cs +++ b/shared/EShopOnAbp.Keycloak.DbMigrator/KeycloakDataSeeder.cs @@ -39,7 +39,7 @@ public class KeyCloakDataSeeder : IDataSeedContributor, ITransientDependency { await UpdateRealmSettingsAsync(); await UpdateAdminUserAsync(); - await CreateRoleMapperAsync(); + await CreateRoleMapperAsync(); // roles scope await CreateClientScopesAsync(); await CreateClientsAsync(); }