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

部署至Azure后调用Itaú银行API遇SSL证书认证错误求助

解决Azure部署后连接Itaú银行API的SSL证书凭据错误

问题描述

集成Itaú银行API生成票据,本地运行时能正常建立连接,部署到Azure服务器后返回以下错误:

无法建立SSL连接,请查看内部异常。提供给程序包的凭据未被识别 - System.Net.WebException: 无法建立SSL连接,请查看内部异常。提供给程序包的凭据未被识别
---> System.Net.Http.HttpRequestException: 无法建立SSL连接,请查看内部异常。
---> System.ComponentModel.Win32Exception (0x8009030D): 提供给程序包的凭据未被识别

调用API的代码如下:

public async Task<AuthTokenItau> AutenticarItauJwt()
{
    var request = (HttpWebRequest)WebRequest.Create("https://sts.itau.com.br/api/oauth/token");
    request.ContentType = "application/x-www-form-urlencoded";
    request.Method = "POST";

    var dataBody = "grant_type=" + Uri.EscapeDataString("client_credentials");
    dataBody += "&client_id=" + Uri.EscapeDataString("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
    dataBody += "&client_secret=" + Uri.EscapeDataString("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");

    var body = Encoding.ASCII.GetBytes(dataBody);
    request.ContentLength = body.Length;

    string response = "";
    Stream myWriter = null;

    try
    {
        var caminhoCertificado = $@"{_webHostingEnvironment.ContentRootPath}\App_Data\Certificado\certifica_digital.pfx";
        var senhaCertificado = @"senhaZZZZ";

        X509Certificate2 certificate = new X509Certificate2(caminhoCertificado, senhaCertificado, X509KeyStorageFlags.DefaultKeySet);
        request.ClientCertificates.Add(certificate);

        RegistraLog.Log($"Certificado -{certificate.ToString()}");

        myWriter = request.GetRequestStream();
        myWriter.Write(body, 0, body.Length);

        var requestResponse = (HttpWebResponse)request.GetResponse();

        RegistraLog.Log($"Response : {requestResponse.Headers.AllKeys} - {dataBody.ToString()}");

        response = new StreamReader(requestResponse.GetResponseStream()).ReadToEnd();

        RegistraLog.Log($"Response -{response.ToString()}");

        return JsonConvert.DeserializeObject<AuthTokenItau>(response); ;
    }
    catch (Exception ex)
    {
        RegistraLog.Log($"Erro ao solicitar o token.\r\nDetalhe: {ex.Message} - {ex.ToString()}");

        throw new Exception("Erro ao solicitar o token.\r\nDetalhe: " + ex.Message);
    }
    finally
    {
        if (myWriter != null)
            myWriter.Close();
    }
}

完整异常堆栈:

无法建立SSL连接,请查看内部异常。提供给程序包的凭据未被识别 - System.Net.WebException: 无法建立SSL连接,请查看内部异常。提供给程序包的凭据未被识别
---> System.Net.Http.HttpRequestException: 无法建立SSL连接,请查看内部异常。
---> System.ComponentModel.Win32Exception (0x8009030D): 提供给程序包的凭据未被识别
at System.Net.SSPIWrapper.AcquireCredentialsHandle(SSPIInterface secModule, String package, CredentialUse intent, SCHANNEL_CRED scc)
at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(CredentialUse credUsage, SCHANNEL_CRED secureCredential)
at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer)
at System.Net.Security.SecureChannel.AcquireClientCredentials(Byte[]& thumbPrint)
at System.Net.Security.SecureChannel.GenerateToken(Byte[] input, Int32 offset, Int32 count, Byte[]& output)
at System.Net.Security.SecureChannel.NextMessage(Byte[] incoming, Int32 offset, Int32 count)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslStream.ThrowIfExceptional()
at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.b__65_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at System.Net.HttpWebRequest.SendRequest()
at System.Net.HttpWebRequest.GetResponse()
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetResponse()
at EscolaPro.ControleBoleto.AuthItauService.AutenticarItauJwt() in D:\GlobalManage\Repositorio\globalmanage\global-manage-api-web\EscolaPro.ControleBoleto\AuthItauService.cs:line 58

解决方案

1. 调整证书加载的KeyStorageFlags

本地环境用DefaultKeySet没问题,但Azure应用服务的运行身份没有用户证书存储的访问权限。改成以下组合,强制证书加载到机器存储,同时允许密钥持久化和导出:

X509Certificate2 certificate = new X509Certificate2(
    caminhoCertificado, 
    senhaCertificado, 
    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable
);

2. 验证Azure环境中的证书文件

  • 用Azure门户的Kudu工具(访问https://<你的应用名>.scm.azurewebsites.net)检查App_Data\Certificado目录是否存在,PFX文件是否上传完整。
  • 若文件权限有问题,建议将证书上传到Azure Key Vault,通过应用服务的托管身份读取证书,避免文件系统权限限制。

3. 替换HttpWebRequest为HttpClient

HttpWebRequest是.NET旧版API,HttpClient对SSL证书的处理更稳定,且异步支持更完善。重构后的代码示例:

public async Task<AuthTokenItau> AutenticarItauJwt()
{
    var handler = new HttpClientHandler();
    var caminhoCertificado = $@"{_webHostingEnvironment.ContentRootPath}\App_Data\Certificado\certifica_digital.pfx";
    var senhaCertificado = @"senhaZZZZ";

    X509Certificate2 certificate = new X509Certificate2(
        caminhoCertificado, 
        senhaCertificado, 
        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable
    );
    handler.ClientCertificates.Add(certificate);

    using var client = new HttpClient(handler);
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var formData = new Dictionary<string, string>
    {
        {"grant_type", "client_credentials"},
        {"client_id", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"},
        {"client_secret", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"}
    };

    var response = await client.PostAsync("https://sts.itau.com.br/api/oauth/token", new FormUrlEncodedContent(formData));
    response.EnsureSuccessStatusCode();

    var responseContent = await response.Content.ReadAsStringAsync();
    RegistraLog.Log($"Response -{responseContent}");

    return JsonConvert.DeserializeObject<AuthTokenItau>(responseContent);
}

4. 检查Azure应用服务的TLS设置

在Azure门户的应用服务“TLS/SSL设置”中,将最低TLS版本设置为TLS 1.2,Itaú银行API通常要求此版本,避免因TLS版本不兼容导致握手失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 18:40:33