不幸的是,克莱夫瑟里斯获得赏金的答案不起作用。它尝试在 HTTP 服务器管道/处理中工作得太晚以获取客户端证书,但是这个帖子 https://stackoverflow.com/questions/8719416/can-client-certificate-settings-be-configured-in-the-web-config给了我一些想法。
该解决方案基于web.config
这需要对“目录”进行特殊处理(也适用于虚拟文件夹或 WebAPI 路由)。
这是所需的逻辑:
https://www.server.com/acmeapi/ https://www.server.com/acmeapi/** => 带有客户端证书的 SSL
https://www.server.com/ 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] // <== key part!
public class AcmeProviderController : ApiController
{
[HttpGet]
[Route("{userId}")]
public async Task<OutputDto> GetInfo(Guid userId)
{
// do work ...
}
}
上面执行 SSL 客户端验证的实际属性如下。可用于装饰整个控制器或仅装饰特定方法。
public class SslClientCertActionFilterAttribute : ActionFilterAttribute
{
public List<string> AllowedThumbprints = new List<string>()
{
// Replace with the thumbprints the 3rd party
// server will be presenting. You can make checks
// more elaborate but always have thumbprint checking ...
"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;
}
}