真实客户端 IP 还原

This commit is contained in:
2026-08-10 17:35:32 +08:00 Unverified
parent d11d038770
commit f1d6b3d1da
3 changed files with 43 additions and 0 deletions
+7
View File
@@ -2,6 +2,13 @@
ASPNETCORE_ENVIRONMENT=Production ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://0.0.0.0:8080 ASPNETCORE_URLS=http://0.0.0.0:8080
# 反向代理必须在转发请求时设置 X-Forwarded-For 和 X-Forwarded-Proto。
# 仅填写实际直接连接 API 的代理 IP;多个代理依次使用 __0、__1……。
# 使用 Docker 时通常是宿主机/代理容器在 Docker 网络中的 IP,而非访客 IP。
# 默认仅信任 127.0.0.1 和 ::1。
# ReverseProxy__TrustedProxies__0=127.0.0.1
# ReverseProxy__TrustedProxies__1=::1
Database__Provider=MySql Database__Provider=MySql
Database__ApplyMigrationsOnStartup=false Database__ApplyMigrationsOnStartup=false
Database__CommandTimeoutSeconds=30 Database__CommandTimeoutSeconds=30
+30
View File
@@ -1,4 +1,5 @@
using System.Text; using System.Text;
using System.Net;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Jiaowu.Api.Domain.Identity; using Jiaowu.Api.Domain.Identity;
using Jiaowu.Api.Domain.System; using Jiaowu.Api.Domain.System;
@@ -20,6 +21,7 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.RateLimiting; using Microsoft.AspNetCore.RateLimiting;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -111,6 +113,21 @@ var rabbitMqOptions = builder.Configuration
var ssoOptions = builder.Configuration var ssoOptions = builder.Configuration
.GetSection(SsoOptions.SectionName) .GetSection(SsoOptions.SectionName)
.Get<SsoOptions>() ?? new SsoOptions(); .Get<SsoOptions>() ?? new SsoOptions();
var trustedProxyAddresses = builder.Configuration
.GetSection("ReverseProxy:TrustedProxies")
.Get<string[]>() ?? [];
var trustedProxies = trustedProxyAddresses
.Select(value =>
{
if (!IPAddress.TryParse(value, out var address))
{
throw new InvalidOperationException(
$"ReverseProxy:TrustedProxies contains an invalid IP address: '{value}'.");
}
return address;
})
.ToArray();
if (ssoOptions.Enabled && if (ssoOptions.Enabled &&
(string.IsNullOrWhiteSpace(ssoOptions.ClientId) || (string.IsNullOrWhiteSpace(ssoOptions.ClientId) ||
@@ -554,6 +571,18 @@ if (ssoOptions.Enabled)
}); });
} }
builder.Services.AddAuthorization(); builder.Services.AddAuthorization();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.ForwardLimit = 1;
options.KnownIPNetworks.Clear();
options.KnownProxies.Clear();
foreach (var proxy in trustedProxies)
{
options.KnownProxies.Add(proxy);
}
});
builder.Services.AddRateLimiter(options => builder.Services.AddRateLimiter(options =>
{ {
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests; options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
@@ -668,6 +697,7 @@ builder.Services.AddSwaggerGen(options =>
var app = builder.Build(); var app = builder.Build();
app.UseForwardedHeaders();
app.UseExceptionHandler(); app.UseExceptionHandler();
app.UseResponseCompression(); app.UseResponseCompression();
app.Use(async (context, next) => app.Use(async (context, next) =>
+6
View File
@@ -105,6 +105,12 @@
"FrontendBaseUrl": "", "FrontendBaseUrl": "",
"CallbackUrl": "" "CallbackUrl": ""
}, },
"ReverseProxy": {
"TrustedProxies": [
"127.0.0.1",
"::1"
]
},
"Cors": { "Cors": {
"Origins": [ "Origins": [
"capacitor://localhost", "capacitor://localhost",