201 lines
6.8 KiB
C#
201 lines
6.8 KiB
C#
using Asp.Versioning;
|
||
using Azure.Identity;
|
||
using Core.Blueprint.Logging.Configuration;
|
||
using Core.Thalos.Adapters.Contracts;
|
||
using Core.Thalos.Adapters.Extensions;
|
||
using Core.Thalos.Adapters.Services;
|
||
using Core.Thalos.BFF.Api.Services;
|
||
using Core.Thalos.External.ClientConfiguration;
|
||
using Google.Protobuf.WellKnownTypes;
|
||
using Microsoft.AspNetCore.Authentication;
|
||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||
using Microsoft.AspNetCore.ResponseCompression;
|
||
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
|
||
using Microsoft.IdentityModel.Tokens;
|
||
using Microsoft.OpenApi.Any;
|
||
using Microsoft.OpenApi.Interfaces;
|
||
using Microsoft.OpenApi.Models;
|
||
using OpenTelemetry.Logs;
|
||
using OpenTelemetry.Resources;
|
||
using Swashbuckle.AspNetCore.SwaggerUI;
|
||
using System.IO.Compression;
|
||
using System.Reflection;
|
||
using System.Security.Claims;
|
||
|
||
var builder = WebApplication.CreateBuilder(args);
|
||
|
||
builder.Configuration
|
||
.AddUserSecrets(Assembly.GetExecutingAssembly())
|
||
.AddEnvironmentVariables();
|
||
|
||
// 🔑 Google Auth config
|
||
var googleClientId = builder.Configuration["Authentication:Google:ClientId"];
|
||
var googleClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
|
||
var redirectUri = builder.Configuration["Authentication:Google:RedirectUri"];
|
||
|
||
// 🧩 Authentication
|
||
builder.Services.AddAuthentication(options =>
|
||
{
|
||
options.DefaultAuthenticateScheme = Constant.Scheme;
|
||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||
})
|
||
.AddScheme<AuthenticationSchemeOptions,
|
||
GoogleAccessTokenAuthenticationHandler>(Constant.Scheme, null)
|
||
.AddGoogle(options =>
|
||
{
|
||
options.ClientId = googleClientId!;
|
||
options.ClientSecret = googleClientSecret!;
|
||
//options.SaveTokens = true;
|
||
options.CallbackPath = $"/{redirectUri}";
|
||
});
|
||
|
||
builder.Services.AddAuthorization();
|
||
builder.Services.AddScoped<IGoogleAuthHelper, GoogleAuthHelperService>();
|
||
builder.Services.AddScoped<IGoogleAuthorization, GoogleAuthorizationService>();
|
||
builder.Services.AddEndpointsApiExplorer();
|
||
|
||
// 🧩 Swagger + OAuth2
|
||
builder.Services.AddSwaggerGen(opts =>
|
||
{
|
||
const string schemeName = "oauth2";
|
||
|
||
opts.SwaggerDoc("v1",
|
||
new OpenApiInfo { Title = "Core.Thalos.BFF", Version = "v1" });
|
||
|
||
opts.AddSecurityDefinition(schemeName, new OpenApiSecurityScheme
|
||
{
|
||
Type = SecuritySchemeType.OAuth2,
|
||
Scheme = "bearer", // tells Swagger-UI to build an Authorization header
|
||
BearerFormat = "JWT",
|
||
Name = "Authorization",
|
||
In = ParameterLocation.Header,
|
||
|
||
/* ⚠️ The key line – tell Swagger-UI to pick id_token instead of access_token */
|
||
Extensions = new Dictionary<string, IOpenApiExtension>
|
||
{
|
||
["x-tokenName"] = new OpenApiString("id_token")
|
||
},
|
||
|
||
Flows = new OpenApiOAuthFlows
|
||
{
|
||
AuthorizationCode = new OpenApiOAuthFlow
|
||
{
|
||
AuthorizationUrl = new Uri("https://accounts.google.com/o/oauth2/v2/auth"),
|
||
TokenUrl = new Uri("https://oauth2.googleapis.com/token"),
|
||
Scopes = new Dictionary<string, string>
|
||
{
|
||
{ "openid", "OpenID Connect" },
|
||
{ "email", "Access email" },
|
||
{ "profile", "Access profile" }
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// every operation requires the scheme
|
||
opts.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||
{
|
||
[new OpenApiSecurityScheme
|
||
{
|
||
Reference = new OpenApiReference
|
||
{ Type = ReferenceType.SecurityScheme, Id = schemeName }
|
||
}
|
||
] = new[] { "openid", "email", "profile" }
|
||
});
|
||
});
|
||
|
||
// 🎯 Existing configs (unchanged)
|
||
builder.Services.AddResponseCompression();
|
||
builder.Services.AddProblemDetails();
|
||
builder.Services.AddLogs(builder);
|
||
builder.Services.AddMemoryCache();
|
||
builder.Services.AddResponseCaching(options => { options.UseCaseSensitivePaths = true; });
|
||
|
||
builder.Logging.AddOpenTelemetry(logging =>
|
||
{
|
||
logging.IncludeScopes = true;
|
||
logging.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("core.thalos.bff.api"))
|
||
.AddConsoleExporter();
|
||
});
|
||
|
||
builder.Host.ConfigureServices((context, services) =>
|
||
{
|
||
services.AddHsts(options =>
|
||
{
|
||
options.Preload = true;
|
||
options.IncludeSubDomains = true;
|
||
options.MaxAge = TimeSpan.FromDays(60);
|
||
});
|
||
|
||
services.AddHttpsRedirection(options => { options.RedirectStatusCode = 308; });
|
||
services.AddAntiforgery();
|
||
services.AddHttpLogging(http => http.CombineLogs = true);
|
||
services.AddCors(options => options.AddPolicy("AllowAll", policy => policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
|
||
|
||
services.AddMvc().AddJsonOptions(opt =>
|
||
{
|
||
opt.JsonSerializerOptions.WriteIndented = true;
|
||
opt.JsonSerializerOptions.MaxDepth = 20;
|
||
opt.JsonSerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals;
|
||
});
|
||
|
||
services.Configure<BrotliCompressionProviderOptions>(opt => opt.Level = CompressionLevel.SmallestSize);
|
||
services.Configure<GzipCompressionProviderOptions>(opt => opt.Level = CompressionLevel.SmallestSize);
|
||
services.AddResponseCompression(opt =>
|
||
{
|
||
opt.EnableForHttps = true;
|
||
opt.Providers.Add<BrotliCompressionProvider>();
|
||
opt.Providers.Add<GzipCompressionProvider>();
|
||
});
|
||
|
||
services.AddControllers();
|
||
services.AddHttpContextAccessor();
|
||
services.AddTransient<TrackingMechanismExtension>();
|
||
services.RegisterExternalLayer(builder.Configuration);
|
||
|
||
services.AddApiVersioning(options => options.ReportApiVersions = true)
|
||
.AddApiExplorer(opt =>
|
||
{
|
||
opt.GroupNameFormat = "'v'VVV";
|
||
opt.SubstituteApiVersionInUrl = true;
|
||
});
|
||
});
|
||
|
||
builder.Services.AddScoped<ITokenService, TokenService>();
|
||
|
||
var app = builder.Build();
|
||
|
||
app.UseDeveloperExceptionPage();
|
||
|
||
app.UseSwagger();
|
||
|
||
app.UseCors(options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().WithOrigins("https://localhost:7239"));
|
||
app.UseSwaggerUI(options =>
|
||
{
|
||
foreach (var version in app.DescribeApiVersions().Select(v => v.GroupName))
|
||
options.SwaggerEndpoint($"/swagger/{version}/swagger.json", version);
|
||
|
||
options.DisplayRequestDuration();
|
||
options.EnableTryItOutByDefault();
|
||
options.DocExpansion(DocExpansion.None);
|
||
|
||
options.OAuthClientId(googleClientId);
|
||
options.OAuthClientSecret(googleClientSecret);
|
||
options.OAuthUsePkce();
|
||
options.OAuthScopes("openid", "email", "profile");
|
||
});
|
||
|
||
app.UseResponseCompression();
|
||
app.UseResponseCaching();
|
||
app.UseHttpsRedirection();
|
||
|
||
app.UseAuthentication();
|
||
app.UseAuthorization();
|
||
app.MapControllers();
|
||
app.UseHsts();
|
||
app.UseAntiforgery();
|
||
app.UseLogging(builder.Configuration);
|
||
app.Run();
|