【问题标题】:HttpRequestMessage.GetClientCertificate() not working with Azure FunctionHttpRequestMessage.GetClientCertificate() 不适用于 Azure 函数
【发布时间】:2017-09-14 03:16:10
【问题描述】:

我已经编写了以下 azure 函数..(问题的快速和简短版本)

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace GranadaCoder.AzurePoc.AzureFunctionsOne
{
    public static class ClientCertificateTest
    {
        [FunctionName("ClientCertificateTestFunctionName")]
        public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
        {
            try
            {
                System.Security.Cryptography.X509Certificates.X509Certificate2 cert = req.GetClientCertificate();

                X509Certificate2 headerCert = null;
                System.Net.Http.Headers.HttpRequestHeaders headers = req.Headers;
                if (headers.Any(x => x.Key.Equals("X-ARR-ClientCert", StringComparison.OrdinalIgnoreCase)))
                {
                    IEnumerable<string> headerValues = headers.GetValues("X-ARR-ClientCert");
                    if (null != headerValues)
                    {
                        var certHeader = headerValues.FirstOrDefault();
                        byte[] clientCertBytes = Convert.FromBase64String(certHeader);
                        headerCert = new X509Certificate2(clientCertBytes);
                    }
                }

                string msg = (null == cert ? "NO CERT :(" : string.Format("We got a cert! '{0}'", cert.Subject)) + " " + (null == headerCert ? "NO headerCert :(" : string.Format("We got a headerCert! '{0}'", headerCert.Subject));

                HttpContent content = req.Content;
                string contentString = content.ReadAsStringAsync().Result;

                msg += String.IsNullOrEmpty(contentString) ? ", no content" : ", " + contentString;

                return req.CreateResponse(HttpStatusCode.OK, msg);
            }
            catch (Exception ex)
            {
                string errorMsg = ex.Message; //  ExceptionHelper.GenerateFullFlatMessage(ex);
                log.Error(errorMsg);
                return req.CreateResponse(HttpStatusCode.BadRequest, errorMsg);
            }
        }
    }
}

我编写了以下“客户端”代码。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace GranadaCoder.SendWebRequests.ConsoleOne
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("START : {0}", System.Diagnostics.Process.GetCurrentProcess().ProcessName);

                X509Certificate2 clientCert = GetClientCertificate("MySelfSignedCertificatePrivateKeyVersion");
                WebRequestHandler requestHandler = new WebRequestHandler();
                requestHandler.ClientCertificates.Add(clientCert);

                HttpClient client = new HttpClient(requestHandler)
                {
                    BaseAddress = new Uri("http://localhost:7071/")
                };

                var pairs = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("login", "abc")
                };

                var postContent = new FormUrlEncodedContent(pairs);

                HttpResponseMessage hrm = client.PostAsync("api/ClientCertificateTestFunctionName", postContent).Result;
                hrm.EnsureSuccessStatusCode();
                if (hrm.IsSuccessStatusCode)
                {
                }

                HttpContent content = hrm.Content;
                string contentString = content.ReadAsStringAsync().Result;

                Console.WriteLine(hrm);
                Console.WriteLine(contentString);
            }
            catch(Exception ex)
            {
                string errorMsg = GenerateFullFlatMessage(ex, true);
                Console.WriteLine(errorMsg);
            }

            Console.WriteLine("END : {0}", System.Diagnostics.Process.GetCurrentProcess().ProcessName);
            Console.WriteLine(string.Empty);

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();
        }

        private static X509Certificate2 GetClientCertificate(string subjectName)
        {
            X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            try
            {
                userCaStore.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
                X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindBySubjectName, subjectName, true);
                X509Certificate2 clientCertificate = null;
                if (findResult.Count == 1)
                {
                    clientCertificate = findResult[0];
                }
                else
                {
                    throw new Exception("Unable to locate the correct client certificate.");
                }
                return clientCertificate;
            }
            catch
            {
                throw;
            }
            finally
            {
                userCaStore.Close();
            }
        }

        private static string GenerateFullFlatMessage(Exception ex, bool showStackTrace)
        {
            string returnValue;

            StringBuilder sb = new StringBuilder();
            Exception nestedEx = ex;

            while (nestedEx != null)
            {
                if (!string.IsNullOrEmpty(nestedEx.Message))
                {
                    sb.Append(nestedEx.Message + System.Environment.NewLine);
                }

                if (showStackTrace && !string.IsNullOrEmpty(nestedEx.StackTrace))
                {
                    sb.Append(nestedEx.StackTrace + System.Environment.NewLine);
                }

                nestedEx = nestedEx.InnerException;
            }

            returnValue = sb.ToString();

            return returnValue;
        }
    }
}

客户端代码正确获取证书。 MySelfSignedCertificatePrivateKeyVersion 是自签名的,它具有私钥。签署此自签名证书的 CA 在我的信任根授权中。

Azure 函数看不到客户端证书。

我的客户回复是:

“没有 CERT :(, login=abc”

为什么 HttpRequestMessage.GetClientCertificate() 失败?

我知道有些东西在起作用,因为我在 azure-function 和响应上看到了“abc”。

注意,我在 Visual Studio 2017 中以调试模式运行我的 azure 函数。

追加:

根据 Tom-Sun 的回答,当函数存在于 azure 中时,我能够让它工作。

这是我稍作修改的客户端代码。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace GranadaCoder.SendWebRequests.ConsoleOne
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                ////ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

                /////////* Use the below to debug failed verification. */
                ////////ServicePointManager.ServerCertificateValidationCallback =
                ////////    new System.Net.Security.RemoteCertificateValidationCallback((
                ////////        sender,
                ////////        cert,
                ////////        chain,
                ////////        ssl) =>
                ////////{
                ////////    Console.WriteLine("ServerCertificateValidationCallback for Cert.Subject : '{0}'", cert.Subject);
                ////////    System.Net.HttpWebRequest hwr = sender as System.Net.HttpWebRequest;
                ////////    if (null != hwr)
                ////////    {
                ////////        SecurityShower.ShowHttpWebRequest(hwr);
                ////////    }

                ////////    //SecurityShower.ShowCertAndChain(cert, chain);
                ////////    return true;
                ////////});


                Console.WriteLine("START : {0}", System.Diagnostics.Process.GetCurrentProcess().ProcessName);

                /* the kind of cert matters this one works, this kind of  certificate  worked
                 X509Extension.X509KeyUsageExtension.KeyUsages = 'CrlSign, KeyCertSign' */
                string thumbPrint = "0123456789012345678901234567890123456789";

                /* certicate that would not work */
                /*X509Extension.X509KeyUsageExtension.KeyUsages = 'KeyEncipherment, DigitalSignature' */
                //thumbPrint = "1234567890123456789012345678901234567890";

                X509Certificate2 clientCert = GetClientCertificate(thumbPrint);
                WebRequestHandler requestHandler = new WebRequestHandler();
                requestHandler.ClientCertificates.Add(clientCert);

                /* local not working */
                string baseUrl = "http://localhost:7071/";
                string suffixUrl = "api/ClientCertificateTestFunctionName";

                /* remote (azure published */
                baseUrl = "https://yourFunctionNameHere.azurewebsites.net/";
                suffixUrl = "api/ClientCertificateTestFunctionName";

                /* some vodoo to create the queryString, the "code" value is gotten via the azure-portal "Get function URL" while on the properties page of the azure function... NOTE, I had to get this value before I change clientCertEnabled to true (aka, when it was clientCertEnabled was false)  after I changed clientCertEnabled to true, the "extra" querystring of the azure function was not showing */
                var builder = new UriBuilder("http://www.wontactuallybeused.com");
                builder.Port = -1;
                var query = System.Web.HttpUtility.ParseQueryString(builder.Query);
                query["code"] = "NotForYouToSee0123456789012345678901234567890123456789==";
                builder.Query = query.ToString();
                string url = builder.ToString();
                suffixUrl += builder.Query;

                HttpClient client = new HttpClient(requestHandler)
                {
                    BaseAddress = new Uri(baseUrl)
                };

                var pairs = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("login", "abc")
                };

                var postContent = new FormUrlEncodedContent(pairs);

                HttpResponseMessage hrm = client.PostAsync(suffixUrl, postContent).Result;
                //hrm.EnsureSuccessStatusCode();
                if (hrm.IsSuccessStatusCode)
                {
                }

                HttpContent content = hrm.Content;
                string contentString = content.ReadAsStringAsync().Result;

                Console.WriteLine(hrm);
                Console.WriteLine(contentString);
            }
            catch(Exception ex)
            {
                string errorMsg = GenerateFullFlatMessage(ex, true);
                Console.WriteLine(errorMsg);
            }

            Console.WriteLine("END : {0}", System.Diagnostics.Process.GetCurrentProcess().ProcessName);
            Console.WriteLine(string.Empty);

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();
        }

        private static X509Certificate2 GetClientCertificate(string thumbprintValue)
        {
            thumbprintValue = System.Text.RegularExpressions.Regex.Replace(thumbprintValue, @"[^\da-zA-z]", string.Empty).ToUpper();
            X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            try
            {
                userCaStore.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
                X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindByThumbprint, thumbprintValue, true);
                X509Certificate2 clientCertificate = null;
                if (findResult.Count == 1)
                {
                    clientCertificate = findResult[0];
                }
                else
                {
                    throw new Exception("Unable to locate the correct client certificate.");
                }
                return clientCertificate;
            }
            catch
            {
                throw;
            }
            finally
            {
                userCaStore.Close();
            }
        }

        private static string GenerateFullFlatMessage(Exception ex, bool showStackTrace)
        {
            string returnValue;

            StringBuilder sb = new StringBuilder();
            Exception nestedEx = ex;

            while (nestedEx != null)
            {
                if (!string.IsNullOrEmpty(nestedEx.Message))
                {
                    sb.Append(nestedEx.Message + System.Environment.NewLine);
                }

                if (showStackTrace && !string.IsNullOrEmpty(nestedEx.StackTrace))
                {
                    sb.Append(nestedEx.StackTrace + System.Environment.NewLine);
                }

                nestedEx = nestedEx.InnerException;
            }

            returnValue = sb.ToString();

            return returnValue;
        }
    }
}

和一个可选的助手

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace MyNamespace
{
    public static class SecurityShower
    {
        public static void ShowHttpWebRequest(System.Net.HttpWebRequest hwr)
        {
            StringBuilder sb = new StringBuilder();
            if (null != hwr)
            {
                sb.Append("-----------------------------------------------HttpWebRequest" + System.Environment.NewLine);
                sb.Append(string.Format("HttpWebRequest.Address.AbsolutePath='{0}'", hwr.Address.AbsolutePath) + System.Environment.NewLine);
                sb.Append(string.Format("HttpWebRequest.Address.AbsoluteUri='{0}'", hwr.Address.AbsoluteUri) + System.Environment.NewLine);
                sb.Append(string.Format("HttpWebRequest.Address='{0}'", hwr.Address) + System.Environment.NewLine);

                sb.Append(string.Format("HttpWebRequest.RequestUri.AbsolutePath='{0}'", hwr.RequestUri.AbsolutePath) + System.Environment.NewLine);
                sb.Append(string.Format("HttpWebRequest.RequestUri.AbsoluteUri='{0}'", hwr.RequestUri.AbsoluteUri) + System.Environment.NewLine);
                sb.Append(string.Format("HttpWebRequest.RequestUri='{0}'", hwr.RequestUri) + System.Environment.NewLine);

                foreach (X509Certificate cert in hwr.ClientCertificates)
                {
                    sb.Append("START*************************************************");
                    ShowX509Certificate(sb, cert);
                    sb.Append("END*************************************************");
                }
            }

            string result = sb.ToString();
            Console.WriteLine(result);
        }

        public static void ShowCertAndChain(X509Certificate2 cert)
        {
            X509Chain chain = new X509Chain();
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;

            ////chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreCtlSignerRevocationUnknown &&
            ////X509VerificationFlags.IgnoreRootRevocationUnknown &&
            ////X509VerificationFlags.IgnoreEndRevocationUnknown &&
            ////X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown &&
            ////X509VerificationFlags.IgnoreCtlNotTimeValid;

            chain.Build(cert);

            ShowCertAndChain(cert, chain);
        }

        public static void ShowCertAndChain(X509Certificate cert, X509Chain chain)
        {
            StringBuilder sb = new StringBuilder();
            if (null != cert)
            {
                ShowX509Certificate(sb, cert);
            }

            if (null != chain)
            {
                sb.Append("-X509Chain(Start)-" + System.Environment.NewLine);
                ////sb.Append(string.Format("Cert.ChainStatus='{0}'", string.Join(",", chain.ChainStatus.ToList())) + System.Environment.NewLine);

                foreach (X509ChainStatus cstat in chain.ChainStatus)
                {
                    sb.Append(string.Format("X509ChainStatus::'{0}'-'{1}'", cstat.Status.ToString(), cstat.StatusInformation) + System.Environment.NewLine);
                }

                X509ChainElementCollection ces = chain.ChainElements;
                ShowX509ChainElementCollection(sb, ces);
                sb.Append("-X509Chain(End)-" + System.Environment.NewLine);
            }

            string result = sb.ToString();
            Console.WriteLine(result);
        }

        private static void ShowX509Extension(StringBuilder sb, int x509ExtensionCount, X509Extension ext)
        {
            sb.Append(string.Empty + System.Environment.NewLine);
            sb.Append(string.Format("--------X509ExtensionNumber(Start):{0}", x509ExtensionCount) + System.Environment.NewLine);
            sb.Append(string.Format("X509Extension.Critical='{0}'", ext.Critical) + System.Environment.NewLine);

            AsnEncodedData asndata = new AsnEncodedData(ext.Oid, ext.RawData);
            sb.Append(string.Format("Extension type: {0}", ext.Oid.FriendlyName) + System.Environment.NewLine);
            sb.Append(string.Format("Oid value: {0}", asndata.Oid.Value) + System.Environment.NewLine);
            sb.Append(string.Format("Raw data length: {0} {1}", asndata.RawData.Length, Environment.NewLine) + System.Environment.NewLine);
            sb.Append(asndata.Format(true) + System.Environment.NewLine);

            X509BasicConstraintsExtension basicEx = ext as X509BasicConstraintsExtension;
            if (null != basicEx)
            {
                sb.Append("-X509BasicConstraintsExtension-" + System.Environment.NewLine);
                sb.Append(string.Format("X509Extension.X509BasicConstraintsExtension.CertificateAuthority='{0}'", basicEx.CertificateAuthority) + System.Environment.NewLine);
            }

            X509EnhancedKeyUsageExtension keyEx = ext as X509EnhancedKeyUsageExtension;
            if (null != keyEx)
            {
                sb.Append("-X509EnhancedKeyUsageExtension-" + System.Environment.NewLine);
                sb.Append(string.Format("X509Extension.X509EnhancedKeyUsageExtension.EnhancedKeyUsages='{0}'", keyEx.EnhancedKeyUsages) + System.Environment.NewLine);
                foreach (Oid oi in keyEx.EnhancedKeyUsages)
                {
                    sb.Append(string.Format("------------EnhancedKeyUsages.Oid.FriendlyName='{0}'", oi.FriendlyName) + System.Environment.NewLine);
                    sb.Append(string.Format("------------EnhancedKeyUsages.Oid.Value='{0}'", oi.Value) + System.Environment.NewLine);
                }
            }

            X509KeyUsageExtension usageEx = ext as X509KeyUsageExtension;
            if (null != usageEx)
            {
                sb.Append("-X509KeyUsageExtension-" + System.Environment.NewLine);
                sb.Append(string.Format("X509Extension.X509KeyUsageExtension.KeyUsages='{0}'", usageEx.KeyUsages) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.CrlSign='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.CrlSign) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.DataEncipherment='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.DataEncipherment) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.DecipherOnly='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.DecipherOnly) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.DigitalSignature='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.DigitalSignature) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.EncipherOnly='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.EncipherOnly) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.KeyAgreement='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.KeyAgreement) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.KeyCertSign='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.KeyCertSign) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.KeyEncipherment='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.KeyEncipherment) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.None='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.None) != 0) + System.Environment.NewLine);
                sb.Append(string.Format("X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.NonRepudiation='{0}'", (usageEx.KeyUsages & X509KeyUsageFlags.NonRepudiation) != 0) + System.Environment.NewLine);
            }

            X509SubjectKeyIdentifierExtension skIdEx = ext as X509SubjectKeyIdentifierExtension;
            if (null != skIdEx)
            {
                sb.Append("-X509SubjectKeyIdentifierExtension-" + System.Environment.NewLine);
                sb.Append(string.Format("X509Extension.X509SubjectKeyIdentifierExtension.Oid='{0}'", skIdEx.Oid) + System.Environment.NewLine);
                sb.Append(string.Format("X509Extension.X509SubjectKeyIdentifierExtension.SubjectKeyIdentifier='{0}'", skIdEx.SubjectKeyIdentifier) + System.Environment.NewLine);
            }

            sb.Append(string.Format("--------X509ExtensionNumber(End):{0}", x509ExtensionCount) + System.Environment.NewLine);
        }

        private static void ShowX509Extensions(StringBuilder sb, string cert2SubjectName, X509ExtensionCollection extColl)
        {
            int x509ExtensionCount = 0;
            sb.Append(string.Format("--------ShowX509Extensions(Start):for:{0}", cert2SubjectName) + System.Environment.NewLine);
            foreach (X509Extension ext in extColl)
            {
                ShowX509Extension(sb, ++x509ExtensionCount, ext);
            }

            sb.Append(string.Format("--------ShowX509Extensions(End):for:{0}", cert2SubjectName) + System.Environment.NewLine);
        }

        private static void ShowX509Certificate2(StringBuilder sb, X509Certificate2 cert2)
        {
            if (null != cert2)
            {
                sb.Append(string.Format("X509Certificate2.SubjectName.Name='{0}'", cert2.SubjectName.Name) + System.Environment.NewLine);
                sb.Append(string.Format("X509Certificate2.Subject='{0}'", cert2.Subject) + System.Environment.NewLine);
                sb.Append(string.Format("X509Certificate2.Thumbprint='{0}'", cert2.Thumbprint) + System.Environment.NewLine);
                sb.Append(string.Format("X509Certificate2.HasPrivateKey='{0}'", cert2.HasPrivateKey) + System.Environment.NewLine);
                sb.Append(string.Format("X509Certificate2.Version='{0}'", cert2.Version) + System.Environment.NewLine);
                sb.Append(string.Format("X509Certificate2.NotBefore='{0}'", cert2.NotBefore) + System.Environment.NewLine);
                sb.Append(string.Format("X509Certificate2.NotAfter='{0}'", cert2.NotAfter) + System.Environment.NewLine);
                sb.Append(string.Format("X509Certificate2.PublicKey.Key.KeySize='{0}'", cert2.PublicKey.Key.KeySize) + System.Environment.NewLine);

                ////List<X509KeyUsageExtension> keyUsageExtensions = cert2.Extensions.OfType<X509KeyUsageExtension>().ToList();
                ////List<X509Extension> extensions = cert2.Extensions.OfType<X509Extension>().ToList();

                ShowX509Extensions(sb, cert2.Subject, cert2.Extensions);
            }
        }

        private static void ShowX509ChainElementCollection(StringBuilder sb, X509ChainElementCollection ces)
        {
            int x509ChainElementCount = 0;
            foreach (X509ChainElement ce in ces)
            {
                sb.Append(string.Empty + System.Environment.NewLine);
                sb.Append(string.Format("----X509ChainElementNumber:{0}", ++x509ChainElementCount) + System.Environment.NewLine);
                sb.Append(string.Format("X509ChainElement.Cert.SubjectName.Name='{0}'", ce.Certificate.SubjectName.Name) + System.Environment.NewLine);
                sb.Append(string.Format("X509ChainElement.Cert.Issuer='{0}'", ce.Certificate.Issuer) + System.Environment.NewLine);
                sb.Append(string.Format("X509ChainElement.Cert.Thumbprint='{0}'", ce.Certificate.Thumbprint) + System.Environment.NewLine);
                sb.Append(string.Format("X509ChainElement.Cert.HasPrivateKey='{0}'", ce.Certificate.HasPrivateKey) + System.Environment.NewLine);

                X509Certificate2 cert2 = ce.Certificate as X509Certificate2;
                ShowX509Certificate2(sb, cert2);

                ShowX509Extensions(sb, cert2.Subject, ce.Certificate.Extensions);
            }
        }

        private static void ShowX509Certificate(StringBuilder sb, X509Certificate cert)
        {
            sb.Append("-----------------------------------------------" + System.Environment.NewLine);
            sb.Append(string.Format("Cert.Subject='{0}'", cert.Subject) + System.Environment.NewLine);
            sb.Append(string.Format("Cert.Issuer='{0}'", cert.Issuer) + System.Environment.NewLine);

            sb.Append(string.Format("Cert.GetPublicKey().Length='{0}'", cert.GetPublicKey().Length) + System.Environment.NewLine);

            X509Certificate2 cert2 = cert as X509Certificate2;
            ShowX509Certificate2(sb, cert2);
        }
    }
}

好读

http://www.razibinrais.com/secure-web-api-with-client-certificate/

【问题讨论】:

  • 对于 Azure WebApps,客户端证书通过请求标头“X-ARR-ClientCert”流向应用程序。见docs.microsoft.com/en-us/azure/app-service-web/…
  • @Suwat。我更改了上面的代码,现在我检查 GetClientCertificate 并检查该标头(X-ARR-ClientCert)并且两者都在那里。我有点想知道 GetClientCertificate 是否只是用于查看该标头的包装器(??)不确定。

标签: azure azure-functions


【解决方案1】:

为什么 HttpRequestMessage.GetClientCertificate() 失败?

我在我这边测试你的代码。我发现,如果我在本地调试它,那么我可以在 Azure 平台上重现您提到的内容,如果我将 clientCertEnabled 更改为 true,那么它可以按预期工作。更多详情请参考Configure Web App for Client Certificate Authentication。如果有人如何在本地启用 clientCertEnabled,请添加评论。

要将您的 Web 应用设置为需要客户端证书,您需要为您的 Web 应用添加 clientCertEnabled 站点设置并将其设置为 true。此设置当前无法通过门户中的管理体验使用,需要使用 REST API 来完成此操作。 您可以使用 ARMClient 工具来轻松制作 REST API 调用。使用该工具登录后,您需要发出以下内容

ARMClient PUT subscriptions/{Subscription Id}/resourcegroups/{Resource Group Name}/providers/Microsoft.Web/sites/{Website Name}?api-version=2015-04-01 @enableclientcert.json -verbose

我将 clientCertEnabled 更改为 azure resources

用客户端代码测试:

注意:目前,如果我们将clientCertEnabled设置为true,那么所有对azure函数的请求都需要认证

【讨论】:

  • 汤姆。您在 Azure-Resources-Explorer 中采用了什么“路径”来实现此设置? (无法通过部分屏幕截图看到)。我现在在附近钓鱼,找不到。
  • Azure Resouce 链接:resources.azure.com,我在回答中也提到了。搜索azure函数名就可以得到,具体可以参考截图。 注意:我们需要更改“读取”->“读取/写入”,然后我们编辑值并将请求放入 Azure 资源。
  • 资源链接:https://resources.azure.com/subscriptions/{Subscription Id}/resourcegroups/{Resource Group Name}/providers/Microsoft.Web/sites/{FunctionAppName}
  • 我拥有“providers/Microsoft.Web/sites/{AzureFunctionAppName}”的一切......这就是我所需要的。谢谢。
  • 我在“idea”网站上发布了这个想法......仅供参考。我认为他们尚未对其进行审核。
猜你喜欢
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-17
相关资源
最近更新 更多