如何添加 ClientCeritifcates,客户端身份验证方案禁止 HTTP 请求 'Anonymous'

How to add ClientCeritifcates, The HTTP request was forbidden with client authentication scheme 'Anonymous'

从自动生成的 Web 服务代理调用方法时出现以下错误 class:

System.ServiceModel.Security.MessageSecurityException was unhandled
HResult=-2146233087 Message=The HTTP request was forbidden with client authentication scheme 'Anonymous'. Source=mscorlib
StackTrace: Server stack trace: at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory'1 factory) at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory'1 factory, WebException responseException, ChannelBinding channelBinding) at System.ServiceModel.Channels.HttpChannelFactory'1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at RPS.LoteNFe.LoteNFeSoap.TesteEnvioLoteRPS(TesteEnvioLoteRPSRequest request) at RPS.LoteNFe.LoteNFeSoapClient.RPS.LoteNFe.LoteNFeSoap.TesteEnvioLoteRPS(TesteEnvioLoteRPSRequest request) in c:\Users\Marcelo\Documents\Visual Studio 2015\Projects\RPS\RPS\Service References\LoteNFe\Reference.cs:line 560 at RPS.LoteNFe.LoteNFeSoapClient.TesteEnvioLoteRPS(Int32 VersaoSchema, String MensagemXML) in c:\Users\Marcelo\Documents\Visual Studio 2015\Projects\RPS\RPS\Service References\LoteNFe\Reference.cs:line 567 at RPS.Assinador.button5_Click(Object sender, EventArgs e) in c:\Users\Marcelo\Documents\Visual Studio 2015\Projects\RPS\RPS\Assinador.cs:line 76 at System.Windows.Forms.Control.OnClick(EventArgs e) at System.Windows.Forms.Button.OnClick(EventArgs e) at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ButtonBase.WndProc(Message& m) at System.Windows.Forms.Button.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at RPS.Program.Main() in c:\Users\Marcelo\Documents\Visual Studio 2015\Projects\RPS\RPS\Program.cs:line 19 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException: System.Net.WebException HResult=-2146233079 Message=The remote server returned an error: (403) Forbidden. Source=System StackTrace: at System.Net.HttpWebRequest.GetResponse() at System.ServiceModel.Channels.HttpChannelFactory'1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) InnerException:

是这样称呼的

X509Certificate2 x509Certificate = new X509Certificate2();
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = ((X509Certificate2Collection)store.Certificates).Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection collection1 = X509Certificate2UI.SelectFromCollection(collection, "Certificados disponiveis", "Selecione o certificado", X509SelectionFlag.SingleSelection);
x509Certificate = collection1[0];

LoteNFeSoapClient loteNFe = new LoteNFeSoapClient();
loteNFe.ClientCredentials.ClientCertificate.SetCertificate(x509Certificate.Subject, StoreLocation.CurrentUser, StoreName.My);
Retorno.Text = loteNFe.TesteEnvioLoteRPS(1, Assinado.Text);

我如何添加此 Web 服务参考:

在 MS Visual Studio 2013 社区中,Project > Add > Service Reference:

Service Reference window

Service Reference advanced settings window

Obs:这些是默认配置。这是一个市政网络服务,用于发送所提供的运输或物流服务的电子发票。

我在某处读到需要添加证书,例如:

LoteNFeSoapClient loteNFe = new LoteNFeSoapClient();
loteNFe.ClientCertificates.Add(clientCertificate);

但这是不可能的,因为:

  1. 这个自动生成的网络服务 class 没有继承自 class 有这个方法 ClientCertificates.Add() 例如 HttpWebClientProtocol class
  2. LoteNFeSoapClient() class 已经继承自 使消息合约匹配之间的值的接口 请求和响应。
  3. 在 c# 中,一个 class 不能有多个基数 class。

那么,可以做什么呢?提前致谢。

已解决,我刚刚使用 wsdl.exe 通过命令行生成了 Web 服务代理 class,这个 class 现在继承自 System.Web.Services.Protocols.SoapHttpClientProtocol,所以我可以使用添加证书

LoteNFe loteNFe = new LoteNFe();
loteNFe.ClientCertificates.Add(x509Certificate);

注意:通过命令行生成的class与使用VS2013生成的完全不同UI。