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
相关产品推荐
相关产品推荐

