Browse Source

Added keycloak migration service

pull/134/head
Galip Tolga Erdem 4 years ago
parent
commit
0306146bad
  1. 7
      EShopOnAbp.sln
  2. 4
      etc/docker/docker-compose.infrastructure.override.yml
  3. 48
      shared/EShopOnAbp.Keycloak.DbMigrator/DbMigratorHostedService.cs
  4. 34
      shared/EShopOnAbp.Keycloak.DbMigrator/EShopOnAbp.Keycloak.DbMigrator.csproj
  5. 21
      shared/EShopOnAbp.Keycloak.DbMigrator/EShopOnAbpDbMigratorModule.cs
  6. 21
      shared/EShopOnAbp.Keycloak.DbMigrator/KeyCloakDataSeeder.cs
  7. 6
      shared/EShopOnAbp.Keycloak.DbMigrator/Keycloak/KeycloakClientOptions.cs
  8. 94
      shared/EShopOnAbp.Keycloak.DbMigrator/Keycloak/KeycloakService.cs
  9. 16
      shared/EShopOnAbp.Keycloak.DbMigrator/Keycloak/Models/AccessTokenResult.cs
  10. 30
      shared/EShopOnAbp.Keycloak.DbMigrator/MigrationService.cs
  11. 35
      shared/EShopOnAbp.Keycloak.DbMigrator/Program.cs
  12. 3
      shared/EShopOnAbp.Keycloak.DbMigrator/appsettings.json

7
EShopOnAbp.sln

@ -43,6 +43,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EShopOnAbp.BasketService",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EShopOnAbp.CmskitService.HttpApi.Host", "services\cmskit\src\EShopOnAbp.CmskitService.HttpApi.Host\EShopOnAbp.CmskitService.HttpApi.Host.csproj", "{D5B9D5A5-44AA-42F8-867C-95B54780C9DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EShopOnAbp.Keycloak.DbMigrator", "shared\EShopOnAbp.Keycloak.DbMigrator\EShopOnAbp.Keycloak.DbMigrator.csproj", "{774C6ADF-BDD0-431C-A9F3-8BAFD5A49C8C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -113,6 +115,10 @@ Global
{D5B9D5A5-44AA-42F8-867C-95B54780C9DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5B9D5A5-44AA-42F8-867C-95B54780C9DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5B9D5A5-44AA-42F8-867C-95B54780C9DC}.Release|Any CPU.Build.0 = Release|Any CPU
{774C6ADF-BDD0-431C-A9F3-8BAFD5A49C8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{774C6ADF-BDD0-431C-A9F3-8BAFD5A49C8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{774C6ADF-BDD0-431C-A9F3-8BAFD5A49C8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{774C6ADF-BDD0-431C-A9F3-8BAFD5A49C8C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -134,6 +140,7 @@ Global
{7AE4C613-780E-4DA5-9B57-76F0D40D5146} = {F415FFFD-E52D-4EBE-98DC-067C1EFFFFE3}
{E373DD66-3247-4D95-B325-064BBBC337B1} = {F415FFFD-E52D-4EBE-98DC-067C1EFFFFE3}
{D5B9D5A5-44AA-42F8-867C-95B54780C9DC} = {F415FFFD-E52D-4EBE-98DC-067C1EFFFFE3}
{774C6ADF-BDD0-431C-A9F3-8BAFD5A49C8C} = {B8B59303-2178-459B-91A8-DF353044E090}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {26F82565-C6A4-439D-93A4-3251E3E7D5B0}

4
etc/docker/docker-compose.infrastructure.override.yml

@ -38,8 +38,8 @@ services:
DB_USER: "postgres"
DB_PASSWORD: "myPassw0rd"
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_HEALTH_ENABLED: true
KEYCLOAK_ADMIN_PASSWORD: "1q2w3E*"
KC_HEALTH_ENABLED: "true"
entrypoint: ["/opt/keycloak/bin/kc.sh", "start-dev"]

48
shared/EShopOnAbp.Keycloak.DbMigrator/DbMigratorHostedService.cs

@ -0,0 +1,48 @@
using System.Threading;
using System.Threading.Tasks;
using EShopOnAbp.DbMigrator.Keycloak;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Volo.Abp;
namespace EShopOnAbp.DbMigrator;
public class DbMigratorHostedService : IHostedService
{
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly IConfiguration _configuration;
public DbMigratorHostedService(
IHostApplicationLifetime hostApplicationLifetime,
IConfiguration configuration)
{
_hostApplicationLifetime = hostApplicationLifetime;
_configuration = configuration;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
using (var application = AbpApplicationFactory.Create<EShopOnAbpDbMigratorModule>(options =>
{
options.Services.ReplaceConfiguration(_configuration);
options.UseAutofac();
options.Services.AddLogging(c => c.AddSerilog());
}))
{
application.Initialize();
await application
.ServiceProvider
.GetRequiredService<MigrationService>()
.MigrateAsync(cancellationToken);
application.Shutdown();
_hostApplicationLifetime.StopApplication();
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

34
shared/EShopOnAbp.Keycloak.DbMigrator/EShopOnAbp.Keycloak.DbMigrator.csproj

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>EShopOnAbp.DbMigrator</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EShopOnAbp.Shared.Hosting\EShopOnAbp.Shared.Hosting.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Logs\**" />
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
</ItemGroup>
<ItemGroup>
<None Remove="appsettings.json" />
<Content Include="appsettings.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

21
shared/EShopOnAbp.Keycloak.DbMigrator/EShopOnAbpDbMigratorModule.cs

@ -0,0 +1,21 @@
using EShopOnAbp.DbMigrator.Keycloak;
using EShopOnAbp.Shared.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace EShopOnAbp.DbMigrator;
[DependsOn(
typeof(EShopOnAbpSharedHostingModule)
)]
public class EShopOnAbpDbMigratorModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddHttpClient(KeycloakService.HttpClientName);
Configure<KeycloakClientOptions>(configuration);
}
}

21
shared/EShopOnAbp.Keycloak.DbMigrator/KeyCloakDataSeeder.cs

@ -0,0 +1,21 @@
using System.Threading.Tasks;
using EShopOnAbp.DbMigrator.Keycloak;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.DbMigrator;
public class KeyCloakDataSeeder : IDataSeedContributor, ITransientDependency
{
private readonly KeycloakService _keycloakService;
public KeyCloakDataSeeder(KeycloakService keycloakService)
{
_keycloakService = keycloakService;
}
public async Task SeedAsync(DataSeedContext context)
{
var result = await _keycloakService.GetAdminAccessTokenAsync("master");
}
}

6
shared/EShopOnAbp.Keycloak.DbMigrator/Keycloak/KeycloakClientOptions.cs

@ -0,0 +1,6 @@
namespace EShopOnAbp.DbMigrator.Keycloak;
public class KeycloakClientOptions
{
}

94
shared/EShopOnAbp.Keycloak.DbMigrator/Keycloak/KeycloakService.cs

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using EShopOnAbp.DbMigrator.Keycloak.Models;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.DbMigrator.Keycloak;
public class KeycloakService : ITransientDependency
{
public const string HttpClientName = "KeycloakServiceHttpClientName";
// TODO: Option
public const string BaseUrl = "http://localhost:8080/admin/realms";
public const string AdminClientId = "admin-cli";
public const string AdminUserName = "admin";
public const string AdminPassword = "1q2w3E*";
private readonly ILogger<KeycloakService> _logger;
private readonly IHttpClientFactory _clientFactory;
public KeycloakService(IHttpClientFactory clientFactory, ILogger<KeycloakService> logger)
{
_clientFactory = clientFactory;
_logger = logger;
}
// public async Task<string> CreateClientAsync(string realm, Client client)
// {
// HttpResponseMessage response = await InternalCreateClientAsync(realm, client).ConfigureAwait(false);
//
// var locationPathAndQuery = response.Headers.Location.PathAndQuery;
// var clientId = response.IsSuccessStatusCode
// ? locationPathAndQuery.Substring(locationPathAndQuery.LastIndexOf("/", StringComparison.Ordinal) + 1)
// : null;
// return clientId;
// }
private HttpClient CreateKeycloakApiHttpClient(string realm)
{
var httpClient = _clientFactory.CreateClient(HttpClientName);
httpClient.BaseAddress = new Uri(BaseUrl);
return httpClient;
}
private async Task<HttpClient> CreateKeycloakApiHttpClientAsync(string realm, string token = null)
{
var httpClient = CreateKeycloakApiHttpClient(realm);
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
if (!string.IsNullOrEmpty(token))
{
var accessToken = await GetAdminAccessTokenAsync(realm);
httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue($"Bearer", $"{accessToken}");
}
return httpClient;
}
public async Task<string> GetAdminAccessTokenAsync(string realm)
{
var httpClient = _clientFactory.CreateClient(HttpClientName);
httpClient.BaseAddress = new Uri(BaseUrl);
var result = string.Empty;
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", AdminClientId),
new KeyValuePair<string, string>("username", AdminUserName),
new KeyValuePair<string, string>("password", AdminPassword),
new KeyValuePair<string, string>("grant_type", "password")
});
var httpResponseMessage =
await httpClient.PostAsync($"/realms/{realm}/protocol/openid-connect/token", formContent);
if (httpResponseMessage.IsSuccessStatusCode)
{
var response = await httpResponseMessage.Content.ReadFromJsonAsync<AccessTokenResult>();
result = response?.AccessToken;
}
return result;
}
}

16
shared/EShopOnAbp.Keycloak.DbMigrator/Keycloak/Models/AccessTokenResult.cs

@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
namespace EShopOnAbp.DbMigrator.Keycloak.Models;
public class AccessTokenResult
{
[JsonPropertyName("access_token")] public string AccessToken { get; set; }
[JsonPropertyName("expires_in")] public int Expiration { get; set; }
[JsonPropertyName("refresh_token")] public string RefreshToken { get; set; }
[JsonPropertyName("refresh_expires_in")]
public int RefreshExpiration { get; set; }
[JsonPropertyName("token_type")] public string TokenType { get; set; }
[JsonPropertyName("scope")] public string Scope { get; set; }
}

30
shared/EShopOnAbp.Keycloak.DbMigrator/MigrationService.cs

@ -0,0 +1,30 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.DbMigrator;
public class MigrationService: ITransientDependency
{
private readonly ILogger<MigrationService> _logger;
private readonly IDataSeeder _dataSeeder;
public MigrationService(ILogger<MigrationService> logger, IDataSeeder dataSeeder)
{
_logger = logger;
_dataSeeder = dataSeeder;
}
public async Task MigrateAsync(CancellationToken cancellationToken)
{
// Check if keycloak api is available
//Seed data
await _dataSeeder.SeedAsync();
_logger.LogInformation("Migration completed!");
}
}

35
shared/EShopOnAbp.Keycloak.DbMigrator/Program.cs

@ -0,0 +1,35 @@
using System.Threading.Tasks;
using EShopOnAbp.DbMigrator;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
class Program
{
async static Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
#if DEBUG
.MinimumLevel.Debug()
#else
.MinimumLevel.Information()
#endif
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", $"DbMigrator")
.WriteTo.Async(c => c.File("Logs/logs.txt"))
.WriteTo.Async(c => c.Console())
.CreateLogger();
await CreateHostBuilder(args).RunConsoleAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.AddAppSettingsSecretsJson()
.ConfigureLogging((context, logging) => logging.ClearProviders())
.ConfigureServices((hostContext, services) => { services.AddHostedService<DbMigratorHostedService>(); });
}

3
shared/EShopOnAbp.Keycloak.DbMigrator/appsettings.json

@ -0,0 +1,3 @@
{
}
Loading…
Cancel
Save