很遗憾,获得奖励的cleftheris的答案并不起作用。它试图在HTTP服务器管道/处理过程中太晚地工作以获取客户端证书,但是这篇文章给了我一些思路。
解决方案基于web.config
,调用“目录”的特殊处理(也适用于虚拟文件夹或WebAPI路由)。
这里是期望的逻辑:
https://www.server.com/acmeapi/** => SSL with Client Certs
https://www.server.com/** => SSL
以下是相应的配置:
<configuration>
...
<system.webServer>
<!-- This is for the rest of the site -->
<security>
<access sslFlags="Ssl" />
</security>
</system.webServer>
<!--This is for the 3rd party API endpoint-->
<location path="acmeapi">
<system.webServer>
<security>
<access sslFlags="SslNegotiateCert"/>
</security>
</system.webServer>
</location>
...
</configuration>
额外加分
以上代码将相应地设置SSL握手。现在,您仍然需要在代码中检查客户端SSL证书是否符合您的预期。操作步骤如下:
控制器代码:
[RoutePrefix("acmeapi")]
[SslClientCertActionFilter]
public class AcmeProviderController : ApiController
{
[HttpGet]
[Route("{userId}")]
public async Task<OutputDto> GetInfo(Guid userId)
{
}
}
以下是从上面实际执行SSL客户端验证的属性。可以用来装饰整个控制器或仅特定方法。
public class SslClientCertActionFilterAttribute : ActionFilterAttribute
{
public List<string> AllowedThumbprints = new List<string>()
{
"0011223344556677889900112233445566778899",
"1122334455667788990011223344556677889900"
};
public override void OnActionExecuting(HttpActionContext actionContext)
{
var request = actionContext.Request;
if (!AuthorizeRequest(request))
{
throw new HttpResponseException(HttpStatusCode.Forbidden);
}
}
private bool AuthorizeRequest(HttpRequestMessage request)
{
if (request==null)
throw new ArgumentNullException("request");
var clientCertificate = request.GetClientCertificate();
if (clientCertificate == null || AllowedThumbprints == null || AllowedThumbprints.Count < 1)
{
return false;
}
foreach (var thumbprint in AllowedThumbprints)
{
if (clientCertificate.Thumbprint != null && clientCertificate.Thumbprint.Equals(thumbprint, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
return false;
}
}