You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core子域名路由配置及客户端证书强制要求实现方案

ASP.NET Core 子域名路由限制与客户端证书配置

一、子域名路由限制实现

完全可以在单个ASP.NET Core项目中实现子域名专属路由,核心思路是通过路由约束、中间件或授权策略校验请求的主机头,限制特定端点仅能通过指定子域名访问。

1. 自定义路由约束

创建路由约束类,校验请求的主机是否为目标子域名:

public class SubdomainRouteConstraint : IRouteConstraint
{
    private readonly string _requiredSubdomain;

    public SubdomainRouteConstraint(string requiredSubdomain)
    {
        _requiredSubdomain = requiredSubdomain;
    }

    public bool Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (httpContext?.Request.Host.Host == null) return false;
        
        var hostParts = httpContext.Request.Host.Host.Split('.');
        if (hostParts.Length < 2) return false;
        
        // 检查子域名是否匹配(兼容多级域名场景)
        return hostParts[0].Equals(_requiredSubdomain, StringComparison.OrdinalIgnoreCase);
    }
}

在Program.cs中注册约束并应用到路由:

var builder = WebApplication.CreateBuilder(args);

// 注册自定义路由约束
builder.Services.Configure<RouteOptions>(options =>
{
    options.ConstraintMap["subdomain"] = typeof(SubdomainRouteConstraint);
});

var app = builder.Build();

// 配置路由:仅允许testing子域名访问/test端点
app.MapGet("/test", () => "Testing subdomain access only")
   .RequireHost("{subdomain:subdomain(testing)}.myapp.com");

2. 中间件批量校验

如果需要限制多个端点,可通过中间件统一校验主机头:

var app = builder.Build();

app.Use(async (context, next) =>
{
    var requestPath = context.Request.Path.Value;
    var host = context.Request.Host.Host;

    // 针对/test端点,校验是否为testing子域名
    if (requestPath?.Equals("/test", StringComparison.OrdinalIgnoreCase) == true)
    {
        if (!host.StartsWith("testing.", StringComparison.OrdinalIgnoreCase))
        {
            context.Response.StatusCode = StatusCodes.Status404NotFound;
            await context.Response.WriteAsync("Endpoint not found");
            return;
        }
    }

    await next();
});

app.MapGet("/test", () => "Testing subdomain access only");

3. 授权策略灵活控制

结合授权策略实现更复杂的访问控制(可搭配其他权限校验):

var builder = WebApplication.CreateBuilder(args);

// 注册授权策略
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("TestingSubdomainOnly", policy =>
    {
        policy.RequireAssertion(context =>
        {
            var host = context.Request.Host.Host;
            return host.StartsWith("testing.", StringComparison.OrdinalIgnoreCase);
        });
    });
});

var app = builder.Build();

// 在端点上应用授权策略
app.MapGet("/test", () => "Testing subdomain access only")
   .RequireAuthorization("TestingSubdomainOnly");

二、子域名强制客户端证书配置

针对testing.myapp.com子域名强制要求客户端证书,可根据部署环境选择以下方案:

1. Kestrel 主机专属配置

若直接使用Kestrel作为服务器,可按主机名分别配置证书要求:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // 主域名:不要求客户端证书
    options.ListenAnyIP(443, listenOptions =>
    {
        listenOptions.UseHttps(httpsOptions =>
        {
            httpsOptions.ServerCertificate = new X509Certificate2("path/to/main-cert.pfx", "cert-password");
            httpsOptions.ClientCertificateMode = ClientCertificateMode.NoCertificate;
        });
        listenOptions.UseHostFiltering();
    });

    // Testing子域名:强制要求客户端证书
    options.ListenAnyIP(443, listenOptions =>
    {
        listenOptions.UseHttps(httpsOptions =>
        {
            httpsOptions.ServerCertificate = new X509Certificate2("path/to/testing-cert.pfx", "cert-password");
            httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
            // 可选:校验客户端证书的颁发机构
            httpsOptions.ClientCertificateValidation = (cert, chain, errors) =>
            {
                return errors == SslPolicyErrors.None && cert.Issuer.Equals("Your CA Issuer");
            };
        });
        listenOptions.UseHostFiltering(options => options.AllowedHosts.Add("testing.myapp.com"));
    });
});

var app = builder.Build();

2. 反向代理场景下的中间件校验

若部署在IIS、Nginx等反向代理后,客户端证书会被转发到请求头中,可通过中间件校验:

app.Use(async (context, next) =>
{
    var host = context.Request.Host.Host;
    if (host.Equals("testing.myapp.com", StringComparison.OrdinalIgnoreCase))
    {
        // 从请求头获取客户端证书(不同代理的头名称不同,IIS用X-ARR-ClientCert)
        var certHeader = context.Request.Headers["X-Client-Certificate"].FirstOrDefault();
        if (string.IsNullOrEmpty(certHeader))
        {
            context.Response.StatusCode = StatusCodes.Status403Forbidden;
            await context.Response.WriteAsync("Client certificate required");
            return;
        }

        // 解析并校验证书
        try
        {
            var certificate = new X509Certificate2(Convert.FromBase64String(certHeader));
            // 自定义校验:检查有效期、颁发机构等
            if (!certificate.Verify())
            {
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                await context.Response.WriteAsync("Invalid client certificate");
                return;
            }
        }
        catch
        {
            context.Response.StatusCode = StatusCodes.Status403Forbidden;
            await context.Response.WriteAsync("Invalid client certificate format");
            return;
        }
    }

    await next();
});

3. IIS 站点绑定配置(可选)

若使用IIS部署,可直接在站点绑定中针对testing.myapp.com设置:

  • 打开IIS管理器,找到目标站点,添加HTTPS绑定,指定主机名为testing.myapp.com
  • 进入SSL设置,勾选“要求SSL”和“要求客户端证书”

内容的提问来源于stack exchange,提问作者Szyszka947

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:10:45