RobotNet/RobotNet.IdentityServer/Program.cs
2025-10-15 15:15:53 +07:00

197 lines
7.3 KiB
C#

using BlazorComponentBus;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using MudBlazor.Services;
using NLog.Web;
using Quartz;
using RobotNet.IdentityServer.Components;
using RobotNet.IdentityServer.Components.Account;
using RobotNet.IdentityServer.Components.Layout;
using RobotNet.IdentityServer.Data;
using RobotNet.IdentityServer.Services;
using System.Security.Cryptography.X509Certificates;
using static OpenIddict.Abstractions.OpenIddictConstants;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseNLog();
// builder.AddServiceDefaults();
builder.Services.AddControllers();
builder.Services.AddControllersWithViews();
builder.Services.AddMudServices();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddScoped<ComponentBus>();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<NavMenu>();
builder.Services.AddSingleton<PasswordStrengthService>();
builder.Services.AddSingleton<UserInfoService>();
builder.Services.AddScoped<UserImageService>();
builder.Services.AddScoped<IdentityService>();
builder.Services.AddScoped<IdentityUserAccessor>();
builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(connectionString);
options.UseOpenIddict();
});
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Lockout.AllowedForNewUsers = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.Password.RequireDigit = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
builder.Services.AddQuartz(options =>
{
options.UseSimpleTypeLoader();
options.UseInMemoryStore();
});
builder.Services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true);
builder.Services.AddOpenIddict()
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and models.
// Note: call ReplaceDefaultEntities() to replace the default OpenIddict entities.
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
// Enable Quartz.NET integration.
options.UseQuartz();
})
.AddServer(options =>
{
options.SetIssuer(builder.Configuration["OpenIddictCertificate:Issuer"] ?? throw new InvalidOperationException("OpenIddictCertificate Issuer is not configured."));
// Enable the authorization, logout, token and userinfo endpoints.
options.SetAuthorizationEndpointUris("api/Authorization/connect/authorize")
.SetEndSessionEndpointUris("api/Authorization/connect/logout")
.SetIntrospectionEndpointUris("connect/introspect")
.SetTokenEndpointUris("api/Authorization/connect/token")
.AllowClientCredentialsFlow()
.SetUserInfoEndpointUris("api/Userinfo")
.SetEndUserVerificationEndpointUris("connect/verify");
// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles);
// Note: this sample only uses the authorization code and refresh token
// flows but you can enable the other flows if you need to support
// implicit, password or client credentials.
options.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow()
.AllowClientCredentialsFlow();
if (builder.Environment.IsDevelopment())
{
// Register the signing and encryption credentials.
options.AddDevelopmentEncryptionCertificate()
.AddDevelopmentSigningCertificate();
// Thêm ephemeral encryption key
//options.AddEphemeralEncryptionKey()
// .AddEphemeralSigningKey(); // Thêm signing key tạm thời
}
else if (builder.Environment.IsProduction())
{
// Thêm ephemeral encryption key
// Sử dụng chứng chỉ thực tế
var path = builder.Configuration["OpenIddictCertificate:Path"] ?? throw new InvalidOperationException("Certificate path is not configured.");
var password = builder.Configuration["OpenIddictCertificate:Password"] ?? throw new InvalidOperationException("Certificate password is not configured.");
if (string.IsNullOrEmpty(path) || string.IsNullOrEmpty(password))
{
throw new InvalidOperationException("Certificate path or password is not configured.");
}
var certificate = X509CertificateLoader.LoadPkcs12FromFile(path, password);
options.AddEncryptionCertificate(certificate)
.AddSigningCertificate(certificate);
}
options.UseDataProtection()
.PreferDefaultAccessTokenFormat()
.PreferDefaultAuthorizationCodeFormat()
.PreferDefaultRefreshTokenFormat();
// Register the ASP.NET Core host and configure the ASP.NET Core-specific options.
options.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableEndSessionEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserInfoEndpointPassthrough()
.EnableStatusCodePagesIntegration();
// Can thiệp vào sự kiện logging
})
.AddValidation(options =>
{
// Import the configuration from the local OpenIddict server instance.
options.UseLocalServer();
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
builder.Services.AddCors(options =>
{
options.AddPolicy("RequestAuthorize", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
builder.Services.AddMudServices();
var app = builder.Build();
await app.Services.SeedApplicationDbAsync();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCors("RequestAuthorize");
app.MapControllers();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.MapAdditionalIdentityEndpoints();
app.Run();