Files
agologum/api/Program.cs
Blitblank 4f60336a37
All checks were successful
Build and Deploy API / build-and-deploy (push) Successful in 8s
it was staring me right in the face
2026-04-22 20:21:39 -05:00

138 lines
4.0 KiB
C#

using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using System.Text;
using agologumApi.Models;
using agologumApi.Services;
var builder = WebApplication.CreateBuilder(args);
var key = builder.Configuration["Jwt:Key"];
if(key == null) return;
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddControllers();
// services
builder.Services.AddScoped<UserService>();
builder.Services.AddScoped<ItemService>();
builder.Services.AddScoped<JwtService>();
// configuration for jwt authentication
builder.Services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders()
.AddRoles<IdentityRole>();
builder.Services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters {
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "agologum",
ValidAudience = "agologum",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddAuthorization(options => {
options.AddPolicy(Permission.SensitiveData_Read, policy =>
policy.RequireClaim("permission", Permission.SensitiveData_Read));
options.AddPolicy(Permission.SensitiveData_Modify, policy =>
policy.RequireClaim("permission", Permission.SensitiveData_Modify));
});
// configuration for behind my nginx proxy
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
options.KnownIPNetworks.Clear();
options.KnownProxies.Clear();
});
// Add services to the container.
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
builder.Services.AddCors(options =>
{
options.AddPolicy("dev",
policy =>
{
policy.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// https://www.reddit.com/r/dotnet/comments/1h7vzbs/how_do_you_guys_handle_authorization_on_a_web_api/
// add authorization here
// controllers will have endpoints based on authorization
// frontend is a different story
var app = builder.Build();
app.UseForwardedHeaders();
app.UseCors("dev");
app.UseAuthentication();
app.UseAuthorization();
// Configure the HTTP request pipeline.
if (app.Environment.IsEnvironment("Development")) {
app.MapOpenApi();
app.UseSwagger();
app.UseSwaggerUI();
} else {
app.UseHttpsRedirection();
}
app.MapControllers();
// attempt enitity-framework migrations at startup. love you stack overflow
using (var scope = app.Services.CreateScope()) {
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var retries = 10;
while (retries-- > 0) {
try {
db.Database.Migrate();
break;
} catch {
Thread.Sleep(5000);
}
}
// TODO: abstract this away
// auto seed Identity roles
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
string[] roles = { "guest", "user", "dev", "mod", "admin", "superuser", "role1", "role2" };
foreach(string role in roles) {
if(!await roleManager.RoleExistsAsync(role)) {
await roleManager.CreateAsync(new IdentityRole(role));
}
}
}
app.Run();