feat(server): adds CORS settings

This commit is contained in:
2026-07-18 20:20:28 +02:00
parent 87e74d8afe
commit adfd2e9d6f
3 changed files with 77 additions and 10 deletions
+40 -10
View File
@@ -73,6 +73,44 @@ if (settings.Keycloak.IsConfigured)
builder.Services.AddAuthorization(); builder.Services.AddAuthorization();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
if (settings.Cors.AllowedOrigins.Contains("*"))
{
policy.AllowAnyOrigin();
}
else
{
policy.WithOrigins(settings.Cors.AllowedOrigins);
}
if (settings.Cors.AllowedMethods.Contains("*"))
{
policy.AllowAnyMethod();
}
else
{
policy.WithMethods(settings.Cors.AllowedMethods);
}
if (settings.Cors.AllowedHeaders.Contains("*"))
{
policy.AllowAnyHeader();
}
else
{
policy.WithHeaders(settings.Cors.AllowedHeaders);
}
if (settings.Cors.AllowCredentials)
{
policy.AllowCredentials();
}
});
});
var app = builder.Build(); var app = builder.Build();
var managementStore = app.Services.GetRequiredService<ManagementStore>(); var managementStore = app.Services.GetRequiredService<ManagementStore>();
@@ -87,20 +125,12 @@ if (settings.Keycloak.IsConfigured)
app.UseElmah(); app.UseElmah();
app.UseCors();
app.Use(async (context, next) => app.Use(async (context, next) =>
{ {
context.Response.Headers.AccessControlAllowOrigin = "*";
context.Response.Headers.AccessControlAllowMethods = "GET, POST, PUT, DELETE, PATCH, OPTIONS";
context.Response.Headers.AccessControlAllowHeaders = "Content-Type, Authorization";
context.Response.Headers.XFrameOptions = "DENY"; context.Response.Headers.XFrameOptions = "DENY";
context.Response.Headers.ContentSecurityPolicy = "frame-ancestors 'none'"; context.Response.Headers.ContentSecurityPolicy = "frame-ancestors 'none'";
if (HttpMethods.IsOptions(context.Request.Method))
{
context.Response.StatusCode = StatusCodes.Status204NoContent;
return;
}
await next(); await next();
}); });
+31
View File
@@ -19,6 +19,8 @@ internal sealed class ServerSettings
public KeycloakSettings Keycloak { get; init; } = new(); public KeycloakSettings Keycloak { get; init; } = new();
public CorsSettings Cors { get; init; } = new();
public static ServerSettings FromConfiguration(IConfiguration configuration) public static ServerSettings FromConfiguration(IConfiguration configuration)
{ {
return new ServerSettings return new ServerSettings
@@ -47,6 +49,13 @@ internal sealed class ServerSettings
true, true,
"Authentication:Keycloak:RequireHttpsMetadata", "Authentication:Keycloak:RequireHttpsMetadata",
"REVERSE_LLAMA_KEYCLOAK_REQUIRE_HTTPS_METADATA") "REVERSE_LLAMA_KEYCLOAK_REQUIRE_HTTPS_METADATA")
},
Cors = new CorsSettings
{
AllowedOrigins = ReadStringArray(configuration, ["CORS:AllowedOrigins"]),
AllowedMethods = ReadStringArray(configuration, ["CORS:AllowedMethods"]),
AllowedHeaders = ReadStringArray(configuration, ["CORS:AllowedHeaders"]),
AllowCredentials = ReadBool(configuration, false, "CORS:AllowCredentials")
} }
}; };
} }
@@ -77,10 +86,32 @@ internal sealed class ServerSettings
return bool.TryParse(value, out var parsed) ? parsed : fallback; return bool.TryParse(value, out var parsed) ? parsed : fallback;
} }
private static string[] ReadStringArray(IConfiguration configuration, params string[] keys)
{
var value = Read(configuration, keys);
if (string.IsNullOrWhiteSpace(value))
{
return [];
}
return value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}
private static string NormalizePath(string path) => private static string NormalizePath(string path) =>
path.StartsWith('/') ? path : $"/{path}"; path.StartsWith('/') ? path : $"/{path}";
} }
internal sealed class CorsSettings
{
public string[] AllowedOrigins { get; init; } = ["*"];
public string[] AllowedMethods { get; init; } = ["*"];
public string[] AllowedHeaders { get; init; } = ["*"];
public bool AllowCredentials { get; init; }
}
internal sealed class KeycloakSettings internal sealed class KeycloakSettings
{ {
public string? Authority { get; init; } public string? Authority { get; init; }
+6
View File
@@ -5,5 +5,11 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"CORS": {
"AllowedOrigins": [ "*" ],
"AllowedMethods": [ "GET", "POST", "PUT", "DELETE", "PATCH" ],
"AllowedHeaders": [ "Content-Type", "Authorization" ],
"AllowCredentials": false
},
"AllowedHosts": "*" "AllowedHosts": "*"
} }