Clean up the identity project and make it use services common
This commit is contained in:
parent
7027967568
commit
acd9a6d04b
@ -1,7 +1,11 @@
|
||||
global using Azure.Core;
|
||||
global using Azure.Identity;
|
||||
global using HealthChecks.UI.Client;
|
||||
global using IdentityModel;
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using System.IdentityModel.Tokens.Jwt;
|
||||
global using System.Linq;
|
||||
global using System.Security.Claims;
|
||||
global using System.Text.RegularExpressions;
|
||||
global using System.Threading.Tasks;
|
||||
global using Duende.IdentityServer;
|
||||
global using Duende.IdentityServer.Configuration;
|
||||
global using Duende.IdentityServer.Events;
|
||||
@ -10,53 +14,33 @@ global using Duende.IdentityServer.Models;
|
||||
global using Duende.IdentityServer.Services;
|
||||
global using Duende.IdentityServer.Stores;
|
||||
global using Duende.IdentityServer.Validation;
|
||||
global using IdentityModel;
|
||||
global using Microsoft.AspNetCore.Authentication;
|
||||
global using Microsoft.AspNetCore.Authorization;
|
||||
global using Microsoft.AspNetCore.Builder;
|
||||
global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
global using Microsoft.AspNetCore.Hosting;
|
||||
global using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
global using Microsoft.AspNetCore.Http;
|
||||
global using Microsoft.AspNetCore.Identity;
|
||||
global using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
global using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
global using Microsoft.AspNetCore.Mvc;
|
||||
global using Microsoft.AspNetCore.Mvc.Filters;
|
||||
global using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
global using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
global using Microsoft.EntityFrameworkCore.Metadata;
|
||||
global using Microsoft.EntityFrameworkCore.Migrations;
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API;
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API.Data;
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API.Data;
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API.Models;
|
||||
global using Microsoft.eShopOnContainers.Services.Identity.API.Services;
|
||||
global using Microsoft.Extensions.Configuration;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
global using Microsoft.Extensions.Hosting;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using Microsoft.Extensions.Options;
|
||||
global using Polly;
|
||||
global using System.Collections.Generic;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using System.Data.SqlClient;
|
||||
global using System.IdentityModel.Tokens.Jwt;
|
||||
global using System.Linq;
|
||||
global using System.Security.Claims;
|
||||
global using System.Text.RegularExpressions;
|
||||
global using System.Threading.Tasks;
|
||||
global using System;
|
||||
global using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
global using Services.Common;
|
||||
|
||||
|
||||
|
||||
|
@ -1,69 +0,0 @@
|
||||
namespace Microsoft.AspNetCore.Hosting
|
||||
{
|
||||
public static class IWebHostExtensions
|
||||
{
|
||||
public static bool IsInKubernetes(this IWebHost webHost)
|
||||
{
|
||||
var cfg = webHost.Services.GetService<IConfiguration>();
|
||||
var orchestratorType = cfg.GetValue<string>("OrchestratorType");
|
||||
return orchestratorType?.ToUpper() == "K8S";
|
||||
}
|
||||
|
||||
public static IWebHost MigrateDbContext<TContext>(this IWebHost webHost, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
|
||||
{
|
||||
var underK8s = webHost.IsInKubernetes();
|
||||
|
||||
using var scope = webHost.Services.CreateScope();
|
||||
var services = scope.ServiceProvider;
|
||||
var logger = services.GetRequiredService<ILogger<TContext>>();
|
||||
var context = services.GetService<TContext>();
|
||||
|
||||
try
|
||||
{
|
||||
logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name);
|
||||
|
||||
if (underK8s)
|
||||
{
|
||||
InvokeSeeder(seeder, context, services);
|
||||
}
|
||||
else
|
||||
{
|
||||
var retries = 10;
|
||||
var retry = Policy.Handle<SqlException>()
|
||||
.WaitAndRetry(
|
||||
retryCount: retries,
|
||||
sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||
onRetry: (exception, timeSpan, retry, ctx) =>
|
||||
{
|
||||
logger.LogWarning(exception, "[{prefix}] Error seeding database (attempt {retry} of {retries})", nameof(TContext), retry, retries);
|
||||
});
|
||||
|
||||
//if the sql server container is not created on run docker compose this
|
||||
//migration can't fail for network related exception. The retry options for DbContext only
|
||||
//apply to transient exceptions
|
||||
// Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service)
|
||||
retry.Execute(() => InvokeSeeder(seeder, context, services));
|
||||
}
|
||||
|
||||
logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name);
|
||||
if (underK8s)
|
||||
{
|
||||
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
|
||||
}
|
||||
}
|
||||
|
||||
return webHost;
|
||||
}
|
||||
|
||||
private static void InvokeSeeder<TContext>(Action<TContext, IServiceProvider> seeder, TContext context, IServiceProvider services)
|
||||
where TContext : DbContext
|
||||
{
|
||||
context.Database.Migrate();
|
||||
seeder(context, services);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,68 +4,54 @@
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<UserSecretsId>aspnet-eShopOnContainers.Identity-90487118-103c-4ff0-b9da-e5e26f7ab0c5</UserSecretsId>
|
||||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
|
||||
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" />
|
||||
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" />
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" />
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework" />
|
||||
<PackageReference Include="Duende.IdentityServer.Storage" />
|
||||
<PackageReference Include="Duende.IdentityServer" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" />
|
||||
<PackageReference Include="Microsoft.Web.LibraryManager.Build" />
|
||||
<PackageReference Include="Polly" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" />
|
||||
<PackageReference Include="System.Data.SqlClient" />
|
||||
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" />
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Views\Account\AccessDenied.cshtml" />
|
||||
<None Include="Views\Account\LoggedOut.cshtml" />
|
||||
<None Include="Views\Account\Login.cshtml" />
|
||||
<None Include="Views\Account\Logout.cshtml" />
|
||||
<None Include="Views\Consent\Index.cshtml" />
|
||||
<None Include="Views\Device\Success.cshtml" />
|
||||
<None Include="Views\Device\UserCodeCapture.cshtml" />
|
||||
<None Include="Views\Device\UserCodeConfirmation.cshtml" />
|
||||
<None Include="Views\Diagnostics\Index.cshtml" />
|
||||
<None Include="Views\Grants\Index.cshtml" />
|
||||
<None Include="Views\Home\Index.cshtml" />
|
||||
<None Include="Views\Shared\Error.cshtml" />
|
||||
<None Include="Views\Shared\Redirect.cshtml" />
|
||||
<None Include="Views\Shared\_Layout.cshtml" />
|
||||
<None Include="Views\Shared\_ScopeListItem.cshtml" />
|
||||
<None Include="Views\Shared\_ValidationSummary.cshtml" />
|
||||
<None Include="Views\_ViewImports.cshtml" />
|
||||
<None Include="Views\_ViewStart.cshtml" />
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties appsettings_1json__JsonSchema="" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<ItemGroup>
|
||||
<None Include="Views\Account\AccessDenied.cshtml" />
|
||||
<None Include="Views\Account\LoggedOut.cshtml" />
|
||||
<None Include="Views\Account\Login.cshtml" />
|
||||
<None Include="Views\Account\Logout.cshtml" />
|
||||
<None Include="Views\Consent\Index.cshtml" />
|
||||
<None Include="Views\Device\Success.cshtml" />
|
||||
<None Include="Views\Device\UserCodeCapture.cshtml" />
|
||||
<None Include="Views\Device\UserCodeConfirmation.cshtml" />
|
||||
<None Include="Views\Diagnostics\Index.cshtml" />
|
||||
<None Include="Views\Grants\Index.cshtml" />
|
||||
<None Include="Views\Home\Index.cshtml" />
|
||||
<None Include="Views\Shared\Error.cshtml" />
|
||||
<None Include="Views\Shared\Redirect.cshtml" />
|
||||
<None Include="Views\Shared\_Layout.cshtml" />
|
||||
<None Include="Views\Shared\_ScopeListItem.cshtml" />
|
||||
<None Include="Views\Shared\_ValidationSummary.cshtml" />
|
||||
<None Include="Views\_ViewImports.cshtml" />
|
||||
<None Include="Views\_ViewStart.cshtml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Services.Common\Services.Common.csproj" />
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties appsettings_1json__JsonSchema="" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
|
@ -1,19 +1,12 @@
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
if (builder.Configuration.GetValue<bool>("UseVault", false))
|
||||
{
|
||||
TokenCredential credential = new ClientSecretCredential(
|
||||
builder.Configuration["Vault:TenantId"],
|
||||
builder.Configuration["Vault:ClientId"],
|
||||
builder.Configuration["Vault:ClientSecret"]);
|
||||
builder.Configuration.AddAzureKeyVault(new Uri($"https://{builder.Configuration["Vault:Name"]}.vault.azure.net/"), credential);
|
||||
}
|
||||
builder.AddServiceDefaults();
|
||||
|
||||
builder.Services.AddControllersWithViews();
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddRazorPages();
|
||||
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("IdentityDb")));
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseSqlServer(builder.Configuration.GetConnectionString("IdentityDb")));
|
||||
|
||||
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.AddDefaultTokenProviders();
|
||||
@ -35,23 +28,25 @@ builder.Services.AddIdentityServer(options =>
|
||||
.AddAspNetIdentity<ApplicationUser>()
|
||||
.AddDeveloperSigningCredential(); // Not recommended for production - you need to store your key material somewhere secure
|
||||
|
||||
builder.Services.AddAuthentication();
|
||||
builder.Services.AddHealthChecks()
|
||||
.AddCheck("self", () => HealthCheckResult.Healthy())
|
||||
.AddSqlServer(builder.Configuration.GetConnectionString("IdentityDb"),
|
||||
.AddSqlServer(_ =>
|
||||
builder.Configuration.GetRequiredConnectionString("IdentityDb"),
|
||||
name: "IdentityDB-check",
|
||||
tags: new string[] { "IdentityDB" });
|
||||
|
||||
builder.Services.AddTransient<IProfileService, ProfileService>();
|
||||
builder.Services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();
|
||||
builder.Services.AddTransient<IRedirectService, RedirectService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
var pathBase = builder.Configuration["PATH_BASE"];
|
||||
if (!string.IsNullOrEmpty(pathBase))
|
||||
if (!await app.CheckHealthAsync())
|
||||
{
|
||||
app.UsePathBase(pathBase);
|
||||
return;
|
||||
}
|
||||
|
||||
app.UseServiceDefaults();
|
||||
|
||||
app.UseStaticFiles();
|
||||
|
||||
// This cookie policy fixes login issues with Chrome 80+ using HHTP
|
||||
@ -61,15 +56,6 @@ app.UseIdentityServer();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapDefaultControllerRoute();
|
||||
app.MapHealthChecks("/hc", new HealthCheckOptions()
|
||||
{
|
||||
Predicate = _ => true,
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
app.MapHealthChecks("/liveness", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Name.Contains("self")
|
||||
});
|
||||
|
||||
// Apply database migration automatically. Note that this approach is not
|
||||
// recommended for production scenarios. Consider generating SQL scripts from
|
||||
|
@ -1,4 +1,10 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"IsClusterEnv": "False",
|
||||
"MvcClient": "http://localhost:5100",
|
||||
"SpaClient": "http://localhost:5104",
|
||||
@ -7,12 +13,6 @@
|
||||
"ApplicationInsights": {
|
||||
"InstrumentationKey": ""
|
||||
},
|
||||
"UseVault": false,
|
||||
"Vault": {
|
||||
"Name": "eshop",
|
||||
"ClientId": "your-client-id",
|
||||
"ClientSecret": "your-client-secret"
|
||||
},
|
||||
"TokenLifetimeMinutes": 120,
|
||||
"PermanentTokenLifetimeDays": 365
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<!--
|
||||
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
|
||||
-->
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" hostingModel="InProcess">
|
||||
<environmentVariables>
|
||||
<environmentVariable name="COMPLUS_ForceENC" value="1" />
|
||||
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
|
||||
</environmentVariables>
|
||||
</aspNetCore>
|
||||
</system.webServer>
|
||||
</configuration>
|
@ -292,7 +292,12 @@ public static class CommonExtensions
|
||||
// }
|
||||
// }
|
||||
|
||||
var eventBusSection = configuration.GetRequiredSection("EventBus");
|
||||
var eventBusSection = configuration.GetSection("EventBus");
|
||||
|
||||
if (!eventBusSection.Exists())
|
||||
{
|
||||
return hcBuilder;
|
||||
}
|
||||
|
||||
return eventBusSection["ProviderName"]?.ToLowerInvariant() switch
|
||||
{
|
||||
@ -340,7 +345,13 @@ public static class CommonExtensions
|
||||
// }
|
||||
// }
|
||||
|
||||
var eventBusSection = configuration.GetRequiredSection("EventBus");
|
||||
var eventBusSection = configuration.GetSection("EventBus");
|
||||
|
||||
if (eventBusSection.Exists())
|
||||
{
|
||||
return services;
|
||||
}
|
||||
|
||||
if (string.Equals(eventBusSection["ProviderName"], "ServiceBus", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||
|
Loading…
x
Reference in New Issue
Block a user