34 changed files with 903 additions and 110 deletions
@ -0,0 +1,16 @@ |
|||
using System; |
|||
using Volo.Abp.Domain.Entities.Events.Distributed; |
|||
using Volo.Abp.EventBus; |
|||
|
|||
namespace EShopOnAbp.PublicWeb; |
|||
|
|||
[EventName("EShopOnAbp.Identity.UserLoggedIn")] |
|||
[Serializable] |
|||
public class UserLoggedInEto : EtoBase |
|||
{ |
|||
public Guid Id { get; set; } |
|||
public string Email { get; set; } |
|||
public string Phone { get; set; } |
|||
public string UserName { get; set; } |
|||
public bool IsEmailVerified { get; set; } |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using Volo.Abp.Domain.Entities.Events.Distributed; |
|||
using Volo.Abp.EventBus; |
|||
|
|||
namespace EShopOnAbp.IdentityService.ETOs |
|||
{ |
|||
[EventName("EShopOnAbp.Identity.UserLoggedIn")] |
|||
[Serializable] |
|||
public class UserLoggedInEto : EtoBase |
|||
{ |
|||
public Guid Id { get; set; } |
|||
public string Email { get; set; } |
|||
public string Phone { get; set; } |
|||
public string UserName { get; set; } |
|||
public bool IsEmailVerified { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
using System.Threading.Tasks; |
|||
using EShopOnAbp.IdentityService.ETOs; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace EShopOnAbp.IdentityService; |
|||
|
|||
public class UserLoggedInEventHandler : IDistributedEventHandler<UserLoggedInEto>, ITransientDependency |
|||
{ |
|||
private readonly IdentityUserManager _userManager; |
|||
private readonly ILogger<UserLoggedInEventHandler> _logger; |
|||
|
|||
public UserLoggedInEventHandler(IdentityUserManager userManager, ILogger<UserLoggedInEventHandler> logger) |
|||
{ |
|||
_userManager = userManager; |
|||
_logger = logger; |
|||
} |
|||
|
|||
|
|||
[UnitOfWork] |
|||
public async virtual Task HandleEventAsync(UserLoggedInEto eventData) |
|||
{ |
|||
if (eventData == null) |
|||
{ |
|||
_logger.LogWarning($"Handling UserLoggedInEvent failed! No user information found!"); |
|||
return; |
|||
} |
|||
|
|||
var user = await _userManager.FindByIdAsync(eventData.Id.ToString()); |
|||
|
|||
if (user == null) |
|||
{ |
|||
await CreateCurrentUserAsync(eventData); |
|||
} |
|||
else |
|||
{ |
|||
await UpdateCurrentUserAsync(user, eventData); |
|||
} |
|||
} |
|||
|
|||
protected virtual async Task CreateCurrentUserAsync(UserLoggedInEto userInfo) |
|||
{ |
|||
var user = new IdentityUser( |
|||
userInfo.Id, |
|||
userInfo.UserName, |
|||
userInfo.Email); |
|||
|
|||
user.SetEmailConfirmed(userInfo.IsEmailVerified); |
|||
|
|||
if (!string.IsNullOrEmpty(userInfo.Phone)) |
|||
{ |
|||
user.SetPhoneNumber(userInfo.Phone, false); |
|||
} |
|||
|
|||
// This should run once to sync the admin userIds that seeded by IdentityModule and the Keycloak admin
|
|||
if (userInfo.UserName == "admin") |
|||
{ |
|||
var adminUser = await _userManager.FindByNameAsync("admin"); |
|||
await _userManager.DeleteAsync(adminUser); |
|||
} |
|||
|
|||
var result = await _userManager.CreateAsync(user); |
|||
|
|||
if (!result.Succeeded) |
|||
{ |
|||
throw new AbpException(string.Join('\n', result.Errors)); |
|||
} |
|||
|
|||
_logger.LogInformation($"Handling UserLoggedInEvent... Created new user with Id:{userInfo.Id}"); |
|||
} |
|||
|
|||
protected virtual async Task UpdateCurrentUserAsync(IdentityUser user, UserLoggedInEto userInfo) |
|||
{ |
|||
if (user.Email != userInfo.Email) |
|||
{ |
|||
_logger.LogInformation($"Handling UserLoggedInEvent... Updating the user email with:{userInfo.Email}"); |
|||
await _userManager.SetEmailAsync(user, userInfo.Email); |
|||
} |
|||
|
|||
if (user.PhoneNumber != userInfo.Phone) |
|||
{ |
|||
_logger.LogInformation( |
|||
$"Handling UserLoggedInEvent... Updating the user phone with:{userInfo.Phone}"); |
|||
await _userManager.SetPhoneNumberAsync(user, userInfo.Phone); |
|||
} |
|||
|
|||
if (user.UserName != userInfo.UserName) |
|||
{ |
|||
_logger.LogInformation( |
|||
$"Handling UserLoggedInEvent... Updating the user name with:{userInfo.UserName}"); |
|||
await _userManager.SetUserNameAsync(user, userInfo.UserName); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
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; |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
<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="Keycloak.Net.Core" Version="1.0.20" /> |
|||
</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> |
|||
@ -0,0 +1,25 @@ |
|||
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(); |
|||
|
|||
Configure<KeycloakClientOptions>(options => |
|||
{ |
|||
options.Url = configuration["Keycloak:url"]; |
|||
options.AdminUserName = configuration["Keycloak:adminUsername"]; |
|||
options.AdminPassword = configuration["Keycloak:adminPassword"]; |
|||
options.RealmName = configuration["Keycloak:realmName"]; |
|||
} |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace EShopOnAbp.DbMigrator; |
|||
|
|||
public class KeycloakClientOptions |
|||
{ |
|||
public string Url { get; set; } |
|||
public string AdminUserName { get; set; } |
|||
public string AdminPassword { get; set; } |
|||
public string RealmName { get; set; } |
|||
} |
|||
@ -0,0 +1,307 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Keycloak.Net; |
|||
using Keycloak.Net.Models.Clients; |
|||
using Keycloak.Net.Models.ClientScopes; |
|||
using Keycloak.Net.Models.ProtocolMappers; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EShopOnAbp.DbMigrator; |
|||
|
|||
public class KeyCloakDataSeeder : IDataSeedContributor, ITransientDependency |
|||
{ |
|||
private readonly KeycloakClient _keycloakClient; |
|||
private readonly KeycloakClientOptions _keycloakOptions; |
|||
private readonly ILogger<KeyCloakDataSeeder> _logger; |
|||
private readonly IConfiguration _configuration; |
|||
|
|||
public KeyCloakDataSeeder(IOptions<KeycloakClientOptions> keycloakClientOptions, ILogger<KeyCloakDataSeeder> logger, |
|||
IConfiguration configuration) |
|||
{ |
|||
_logger = logger; |
|||
_configuration = configuration; |
|||
_keycloakOptions = keycloakClientOptions.Value; |
|||
|
|||
_keycloakClient = new KeycloakClient( |
|||
_keycloakOptions.Url, |
|||
_keycloakOptions.AdminUserName, |
|||
_keycloakOptions.AdminPassword |
|||
); |
|||
} |
|||
|
|||
public async Task SeedAsync(DataSeedContext context) |
|||
{ |
|||
await UpdateAdminUserAsync(); |
|||
await CreateRoleMapperAsync(); |
|||
await CreateClientScopesAsync(); |
|||
await CreateClientsAsync(); |
|||
} |
|||
|
|||
private async Task CreateRoleMapperAsync() |
|||
{ |
|||
var roleScope = (await _keycloakClient.GetClientScopesAsync(_keycloakOptions.RealmName)) |
|||
.FirstOrDefault(q => q.Name == "roles"); |
|||
if (roleScope == null) |
|||
return; |
|||
|
|||
if (!roleScope.ProtocolMappers.Any(q => q.Name == "roles")) |
|||
{ |
|||
await _keycloakClient.CreateProtocolMapperAsync(_keycloakOptions.RealmName, roleScope.Id, |
|||
new ProtocolMapper() |
|||
{ |
|||
Name = "roles", |
|||
Protocol = "openid-connect", |
|||
_ProtocolMapper = "oidc-usermodel-realm-role-mapper", |
|||
Config = new Dictionary<string, string>() |
|||
{ |
|||
{ "access.token.claim", "true" }, |
|||
{ "id.token.claim", "true" }, |
|||
{ "claim.name", "roles" }, |
|||
{ "multivalued", "true" }, |
|||
{ "userinfo.token.claim", "true" }, |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
private async Task CreateClientScopesAsync() |
|||
{ |
|||
await CreateScopeAsync("AdministrationService"); |
|||
await CreateScopeAsync("IdentityService"); |
|||
await CreateScopeAsync("BasketService"); |
|||
await CreateScopeAsync("CatalogService"); |
|||
await CreateScopeAsync("OrderingService"); |
|||
await CreateScopeAsync("PaymentService"); |
|||
await CreateScopeAsync("CmskitService"); |
|||
} |
|||
|
|||
private async Task CreateScopeAsync(string scopeName) |
|||
{ |
|||
var scope = (await _keycloakClient.GetClientScopesAsync(_keycloakOptions.RealmName)) |
|||
.FirstOrDefault(q => q.Name == scopeName); |
|||
|
|||
if (scope == null) |
|||
{ |
|||
scope = new ClientScope |
|||
{ |
|||
Name = scopeName, |
|||
Description = scopeName + " scope", |
|||
Protocol = "openid-connect", |
|||
Attributes = new Attributes |
|||
{ |
|||
ConsentScreenText = scopeName, |
|||
DisplayOnConsentScreen = "true", |
|||
IncludeInTokenScope = "true" |
|||
}, |
|||
ProtocolMappers = new List<ProtocolMapper>() |
|||
{ |
|||
new ProtocolMapper() |
|||
{ |
|||
Name = scopeName, |
|||
Protocol = "openid-connect", |
|||
_ProtocolMapper = "oidc-audience-mapper", |
|||
Config = |
|||
new |
|||
Dictionary<string, |
|||
string>() //TODO: Update when //https://github.com/AnderssonPeter/Keycloak.Net/pull/5 is merged
|
|||
{ |
|||
{ "id.token.claim", "false" }, |
|||
{ "access.token.claim", "true" }, |
|||
{ "included.custom.audience", scopeName } |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
await _keycloakClient.CreateClientScopeAsync(_keycloakOptions.RealmName, scope); |
|||
} |
|||
} |
|||
|
|||
private async Task CreateClientsAsync() |
|||
{ |
|||
await CreatePublicWebClientAsync(); |
|||
await CreateSwaggerClientAsync(); // TODO: Test when Volo.Abp.Swashbuckle v6.0.1 is released (https://github.com/abpframework/abp/pull/14409)
|
|||
await CreateWebClientAsync(); |
|||
} |
|||
|
|||
private async Task CreateWebClientAsync() |
|||
{ |
|||
var webClient = (await _keycloakClient.GetClientsAsync(_keycloakOptions.RealmName, clientId: "Web")) |
|||
.FirstOrDefault(); |
|||
|
|||
if (webClient == null) |
|||
{ |
|||
var webRootUrl = _configuration[$"Clients:Web:RootUrl"]; |
|||
webClient = new Client |
|||
{ |
|||
ClientId = "Web", |
|||
Name = "Angular Back-Office Web Application", |
|||
Protocol = "openid-connect", |
|||
Enabled = true, |
|||
BaseUrl = webRootUrl, |
|||
RedirectUris = new List<string> |
|||
{ |
|||
$"{webRootUrl.TrimEnd('/')}" |
|||
}, |
|||
FrontChannelLogout = true, |
|||
PublicClient = true |
|||
}; |
|||
webClient.Attributes = new Dictionary<string, object> |
|||
{ |
|||
{ "post.logout.redirect.uris", $"{webRootUrl.TrimEnd('/')}" } |
|||
}; |
|||
|
|||
await _keycloakClient.CreateClientAsync(_keycloakOptions.RealmName, webClient); |
|||
|
|||
await AddOptionalClientScopesAsync( |
|||
"Web", |
|||
new List<string> |
|||
{ |
|||
"AdministrationService", "IdentityService", "BasketService", "CatalogService", |
|||
"OrderingService", "PaymentService", "CmskitService" |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
private async Task CreateSwaggerClientAsync() |
|||
{ |
|||
var swaggerClient = |
|||
(await _keycloakClient.GetClientsAsync(_keycloakOptions.RealmName, clientId: "SwaggerClient")) |
|||
.FirstOrDefault(); |
|||
|
|||
if (swaggerClient == null) |
|||
{ |
|||
var webGatewaySwaggerRootUrl = _configuration[$"Clients:WebGateway:RootUrl"].TrimEnd('/'); |
|||
var publicWebGatewayRootUrl = _configuration[$"Clients:PublicWebGateway:RootUrl"].TrimEnd('/'); |
|||
var accountServiceRootUrl = _configuration[$"Clients:AccountService:RootUrl"].TrimEnd('/'); |
|||
var identityServiceRootUrl = _configuration[$"Clients:IdentityService:RootUrl"].TrimEnd('/'); |
|||
var administrationServiceRootUrl = _configuration[$"Clients:AdministrationService:RootUrl"].TrimEnd('/'); |
|||
var catalogServiceRootUrl = _configuration[$"Clients:CatalogService:RootUrl"].TrimEnd('/'); |
|||
var basketServiceRootUrl = _configuration[$"Clients:BasketService:RootUrl"].TrimEnd('/'); |
|||
var orderingServiceRootUrl = _configuration[$"Clients:OrderingService:RootUrl"].TrimEnd('/'); |
|||
var paymentServiceRootUrl = _configuration[$"Clients:PaymentService:RootUrl"].TrimEnd('/'); |
|||
var cmskitServiceRootUrl = _configuration[$"Clients:CmskitService:RootUrl"].TrimEnd('/'); |
|||
|
|||
swaggerClient = new Client |
|||
{ |
|||
ClientId = "SwaggerClient", |
|||
Name = "Swagger Client Application", |
|||
Protocol = "openid-connect", |
|||
Enabled = true, |
|||
RedirectUris = new List<string> |
|||
{ |
|||
$"{webGatewaySwaggerRootUrl}/swagger/oauth2-redirect.html", // WebGateway redirect uri
|
|||
$"{publicWebGatewayRootUrl}/swagger/oauth2-redirect.html", // PublicWebGateway redirect uri
|
|||
$"{accountServiceRootUrl}/swagger/oauth2-redirect.html", // AccountService redirect uri
|
|||
$"{identityServiceRootUrl}/swagger/oauth2-redirect.html", // IdentityService redirect uri
|
|||
$"{administrationServiceRootUrl}/swagger/oauth2-redirect.html", // AdministrationService redirect uri
|
|||
$"{catalogServiceRootUrl}/swagger/oauth2-redirect.html", // CatalogService redirect uri
|
|||
$"{basketServiceRootUrl}/swagger/oauth2-redirect.html", // BasketService redirect uri
|
|||
$"{orderingServiceRootUrl}/swagger/oauth2-redirect.html", // OrderingService redirect uri
|
|||
$"{paymentServiceRootUrl}/swagger/oauth2-redirect.html", // PaymentService redirect uri
|
|||
$"{cmskitServiceRootUrl}/swagger/oauth2-redirect.html" // CmskitService redirect uri
|
|||
}, |
|||
FrontChannelLogout = true, |
|||
PublicClient = true |
|||
}; |
|||
|
|||
await _keycloakClient.CreateClientAsync(_keycloakOptions.RealmName, swaggerClient); |
|||
} |
|||
} |
|||
|
|||
private async Task CreatePublicWebClientAsync() |
|||
{ |
|||
var publicWebClient = (await _keycloakClient.GetClientsAsync(_keycloakOptions.RealmName, clientId: "PublicWeb")) |
|||
.FirstOrDefault(); |
|||
|
|||
if (publicWebClient == null) |
|||
{ |
|||
var publicWebRootUrl = _configuration[$"Clients:PublicWeb:RootUrl"]; |
|||
publicWebClient = new Client |
|||
{ |
|||
ClientId = "PublicWeb", |
|||
Name = "Public Web Application", |
|||
Protocol = "openid-connect", |
|||
Enabled = true, |
|||
BaseUrl = publicWebRootUrl, |
|||
RedirectUris = new List<string> |
|||
{ |
|||
$"{publicWebRootUrl.TrimEnd('/')}/signin-oidc" |
|||
}, |
|||
FrontChannelLogout = true, |
|||
PublicClient = true, |
|||
ImplicitFlowEnabled = true // for hybrid flow
|
|||
}; |
|||
publicWebClient.Attributes = new Dictionary<string, object> |
|||
{ |
|||
{ "post.logout.redirect.uris", $"{publicWebRootUrl.TrimEnd('/')}/signout-callback-oidc" } |
|||
}; |
|||
|
|||
await _keycloakClient.CreateClientAsync(_keycloakOptions.RealmName, publicWebClient); |
|||
|
|||
await AddOptionalClientScopesAsync( |
|||
"PublicWeb", |
|||
new List<string> |
|||
{ |
|||
"AdministrationService", "IdentityService", "BasketService", "CatalogService", |
|||
"OrderingService", "PaymentService", "CmskitService" |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
private async Task AddOptionalClientScopesAsync(string clientName, List<string> scopes) |
|||
{ |
|||
var client = (await _keycloakClient.GetClientsAsync(_keycloakOptions.RealmName, clientId: clientName)) |
|||
.FirstOrDefault(); |
|||
if (client == null) |
|||
{ |
|||
_logger.LogError($"Couldn't find {clientName}! Could not seed optional scopes!"); |
|||
return; |
|||
} |
|||
|
|||
var clientOptionalScopes = |
|||
(await _keycloakClient.GetOptionalClientScopesAsync(_keycloakOptions.RealmName, client.Id)).ToList(); |
|||
|
|||
var clientScopes = (await _keycloakClient.GetClientScopesAsync(_keycloakOptions.RealmName)).ToList(); |
|||
|
|||
foreach (var scope in scopes) |
|||
{ |
|||
if (!clientOptionalScopes.Any(q => q.Name == scope)) |
|||
{ |
|||
var serviceScope = clientScopes.First(q => q.Name == scope); |
|||
_logger.LogInformation($"Seeding {scope} scope to {clientName}."); |
|||
await _keycloakClient.UpdateOptionalClientScopeAsync(_keycloakOptions.RealmName, client.Id, |
|||
serviceScope.Id); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private async Task UpdateAdminUserAsync() |
|||
{ |
|||
var users = await _keycloakClient.GetUsersAsync(_keycloakOptions.RealmName, username: "admin"); |
|||
var adminUser = users.FirstOrDefault(); |
|||
if (adminUser == null) |
|||
{ |
|||
throw new Exception( |
|||
"Keycloak admin user is not provided, check if KEYCLOAK_ADMIN environment variable is passed properly."); |
|||
} |
|||
|
|||
if (string.IsNullOrEmpty(adminUser.Email)) |
|||
{ |
|||
adminUser.Email = "admin@abp.io"; |
|||
adminUser.FirstName = "admin"; |
|||
adminUser.EmailVerified = true; |
|||
|
|||
_logger.LogInformation("Updating admin user with email and first name..."); |
|||
await _keycloakClient.UpdateUserAsync(_keycloakOptions.RealmName, adminUser.Id, adminUser); |
|||
} |
|||
} |
|||
} |
|||
@ -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!"); |
|||
} |
|||
|
|||
} |
|||
@ -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>(); }); |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
{ |
|||
"Keycloak": { |
|||
"url": "http://localhost:8080", |
|||
"adminUsername": "admin", |
|||
"adminPassword": "1q2w3E*", |
|||
"realmName": "master" |
|||
}, |
|||
"Clients": { |
|||
"Web": { |
|||
"RootUrl": "http://localhost:4200" |
|||
}, |
|||
"PublicWeb": { |
|||
"RootUrl": "https://localhost:44335" |
|||
}, |
|||
"WebGateway": { |
|||
"RootUrl": "https://localhost:44372" |
|||
}, |
|||
"PublicWebGateway": { |
|||
"RootUrl": "https://localhost:44373" |
|||
}, |
|||
"AccountService": { |
|||
"RootUrl": "https://localhost:44330" |
|||
}, |
|||
"IdentityService": { |
|||
"RootUrl": "https://localhost:44351" |
|||
}, |
|||
"AdministrationService": { |
|||
"RootUrl": "https://localhost:44353" |
|||
}, |
|||
"CatalogService": { |
|||
"RootUrl": "https://localhost:44354" |
|||
}, |
|||
"BasketService": { |
|||
"RootUrl": "https://localhost:44355" |
|||
}, |
|||
"OrderingService": { |
|||
"RootUrl": "https://localhost:44356" |
|||
}, |
|||
"PaymentService": { |
|||
"RootUrl": "https://localhost:44357" |
|||
}, |
|||
"CmskitService": { |
|||
"RootUrl": "https://localhost:44358" |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue