|
|
|
@@ -0,0 +1,85 @@ |
|
|
|
using System.Net; |
|
|
|
using Altob.NtuInvoiceGateway.Models; |
|
|
|
using Microsoft.Extensions.Options; |
|
|
|
|
|
|
|
namespace Altob.NtuInvoiceGateway.Middleware; |
|
|
|
|
|
|
|
public class IpWhitelistMiddleware |
|
|
|
{ |
|
|
|
private readonly RequestDelegate _next; |
|
|
|
private readonly ILogger<IpWhitelistMiddleware> _logger; |
|
|
|
private readonly IpWhitelistOptions _ipWhitelistOptions; |
|
|
|
|
|
|
|
public IpWhitelistMiddleware( |
|
|
|
RequestDelegate next, |
|
|
|
ILogger<IpWhitelistMiddleware> logger, |
|
|
|
IOptions<IpWhitelistOptions> ipWhitelistOptions) |
|
|
|
{ |
|
|
|
_next = next; |
|
|
|
_logger = logger; |
|
|
|
_ipWhitelistOptions = ipWhitelistOptions.Value; |
|
|
|
} |
|
|
|
|
|
|
|
public async Task InvokeAsync(HttpContext context) |
|
|
|
{ |
|
|
|
// 如果 IP 白名單未啟用,直接通過 |
|
|
|
if (!_ipWhitelistOptions.Enabled) |
|
|
|
{ |
|
|
|
await _next(context); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 只對 Test 開頭的頁面進行 IP 白名單檢查 |
|
|
|
var path = context.Request.Path.Value ?? string.Empty; |
|
|
|
if (!path.StartsWith("/Test", StringComparison.OrdinalIgnoreCase)) |
|
|
|
{ |
|
|
|
await _next(context); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var remoteIp = context.Connection.RemoteIpAddress; |
|
|
|
var clientIp = GetClientIp(context); |
|
|
|
|
|
|
|
_logger.LogDebug("IP Whitelist check for Test page - Path: {Path}, RemoteIp: {RemoteIp}, ClientIp: {ClientIp}", |
|
|
|
path, remoteIp, clientIp); |
|
|
|
|
|
|
|
// 檢查 RemoteIp 或 ClientIp 是否在白名單中 |
|
|
|
var isAllowed = false; |
|
|
|
|
|
|
|
if (remoteIp != null && IsIpAllowed(remoteIp.ToString())) |
|
|
|
{ |
|
|
|
isAllowed = true; |
|
|
|
} |
|
|
|
else if (clientIp != null && IsIpAllowed(clientIp)) |
|
|
|
{ |
|
|
|
isAllowed = true; |
|
|
|
} |
|
|
|
|
|
|
|
if (!isAllowed) |
|
|
|
{ |
|
|
|
_logger.LogWarning("{ServiceName} - {ActionName} - {CallerIp} - {ClientIp} - IP access denied to Test page: {Path}", |
|
|
|
"NtuInvoiceGateway", "IpWhitelistCheck", remoteIp?.ToString() ?? "Unknown", clientIp, path); |
|
|
|
|
|
|
|
context.Response.StatusCode = StatusCodes.Status403Forbidden; |
|
|
|
await context.Response.WriteAsync("Access denied. Your IP address is not allowed to access test pages."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
await _next(context); |
|
|
|
} |
|
|
|
|
|
|
|
private bool IsIpAllowed(string ipAddress) |
|
|
|
{ |
|
|
|
return _ipWhitelistOptions.AllowedIps.Contains(ipAddress); |
|
|
|
} |
|
|
|
|
|
|
|
private string? GetClientIp(HttpContext context) |
|
|
|
{ |
|
|
|
var forwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); |
|
|
|
if (!string.IsNullOrEmpty(forwardedFor)) |
|
|
|
{ |
|
|
|
return forwardedFor.Split(',').FirstOrDefault()?.Trim(); |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |