c# - (407) 需要代理身份验证 - 基本身份验证
问题描述
编辑:
经过很长时间的努力解决这个问题,我遇到了一个潜在的解决方案。截至今天(2021 年 10 月 19 日),System.ServiceModel.***
软件包的最新稳定版本是 4.8.1,但有 4.9.0 的候选版本似乎完全解决了我在这里遇到的问题。
我检查了 .NET WCF GitHub 源,发现这个候选版本(版本4.9.0-rc1.21431.2
)正是我正在寻找的。他们已经更新了HttpTransportBindingElement
包含一个Proxy
属性。显然它还不是稳定的版本,但它仍然可以完成工作。有了这个,我能够使用如下所示的东西来解决原始问题:
using (var myWsdlClient = new MyWsdlGeneratedClient())
{
var binding = myWsdlClient.Endpoint.Binding as BasicHttpBinding;
var customBinding = new CustomBinding(binding);
var htbe = customBinding.Elements.Find<HttpTransportBindingElement>();
htbe.AuthenticationScheme = AuthenticationSchemes.Basic;
htbe.ProxyAuthenticationScheme = AuthenticationSchemes.Basic;
htbe.UseDefaultWebProxy = false;
htbe.BypassProxyOnLocal = false;
htbe.Proxy = new WebProxy
{
Address = new Uri("http://myproxyaddress.com:8080"),
/* Proxy creds */
Credentials = new NetworkCredential("MyProxyUserName", "MyProxyPassword"),
BypassProxyOnLocal = false
};
myWsdlClient.Endpoint.Binding = customBinding;
/* Client creds */
myWsdlClient.ClientCredentials.UserName.UserName = "MyClientUserName";
myWsdlClient.ClientCredentials.UserName.Password = "MyClientPassword";
/* Send request */
myWsdlClient.Endpoint.Address = new EndpointAddress("https://myclientaddress.com");
myWsdlClient.doSomeAction(actionRequest); // <-- IT WORKS!!!
}
原始问题:
我正在尝试通过 Web 代理发送 WCF 服务请求,并且收到错误“远程服务器返回错误:(407) 需要代理身份验证”。我已经使用 WSDL 生成了代理类,在我的 app.config 中设置了绑定/端点等(它是一个BasicHttpBinding
. 问题是:客户端和代理都需要基本身份验证,我似乎只能设置客户端凭据,而不是代理。
我已经尝试过的事情:
- 我在网上看到您可以尝试在代理本身的 URL 中传递凭据。所以我以编程方式为
ProxyAddress
绑定上的属性执行此操作,如下所示:
using (var myWsdlClient = new MyWsdlGeneratedClient())
{
var binding = myWsdlClient.Endpoint.Binding as BasicHttpBinding;
/* Client creds */
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
myWsdlClient.ClientCredentials.UserName.UserName = "MyClientUserName";
myWsdlClient.ClientCredentials.UserName.Password = "MyClientPassword";
/* Proxy creds */
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;
binding.UseDefaultWebProxy = false;
binding.BypassProxyOnLocal = false;
binding.ProxyAddress = new Uri("http://MyProxyUserName:MyProxyPassword@myproxyaddress.com:8080");
/* Send request */
myWsdlClient.Endpoint.Address = new EndpointAddress("https://myclientaddress.com");
myWsdlClient.doSomeAction(actionRequest); // <-- error is thrown here, inner exception is 407 HTTP response
}
- 我也尝试使用默认的网络代理(它有点工作)。同样,我以编程方式设置它,如下所示:
using (var myWsdlClient = new MyWsdlGeneratedClient())
{
var binding = myWsdlClient.Endpoint.Binding as BasicHttpBinding;
/* Client creds */
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
myWsdlClient.ClientCredentials.UserName.UserName = "MyClientUserName";
myWsdlClient.ClientCredentials.UserName.Password = "MyClientPassword";
/* Proxy creds */
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;
binding.UseDefaultWebProxy = true;
binding.BypassProxyOnLocal = false;
var defaultProxyBefore = WebRequest.DefaultWebProxy;
var newProxy = new WebProxy
{
Address = new Uri("http://myproxyaddress.com:8080"),
Credentials = new NetworkCredential("MyProxyUserName", "MyProxyPassword"),
BypassProxyOnLocal = false
};
WebRequest.DefaultWebProxy = newProxy;
/* Send request */
myWsdlClient.Endpoint.Address = new EndpointAddress("https://myclientaddress.com");
try
{
myWsdlClient.doSomeAction(actionRequest);
}
finally
{
WebRequest.DefaultWebProxy = defaultProxyBefore;
}
}
第二种方法的好处是它确实有效!但是,对于我的项目的要求,这还不够。我正在开发的应用程序每秒在不同线程上发送大量请求,其中一些通过默认代理。我不希望所有那些不相关的请求都通过我的“新”代理,它们应该继续通过默认值。
总而言之,我需要一种按请求设置代理的方法,同时还能够为客户端和代理设置基本身份验证。我对 WCF 不是很有经验,我只是偶然发现了“自定义绑定”的概念,这似乎很有希望,但我仍然没有发现它是否可以满足我的需求。对此的任何帮助都非常感谢!
解决方案
欢迎来到堆栈溢出。感谢您的详细问题。
“正确”的解决方案是使用 HTTPS 代理(不是 HTTP 代理)。
如果这不可行,您可以将 Binding 的安全模式设置为BasicHttpSecurityMode.TransportCredentialOnly
. (因为基本身份验证未加密,我不建议在生产应用程序中这样做。)
以下是基于您的原始帖子的示例。请让我知道这对你有没有用。
using (var myWsdlClient = new MyWsdlGeneratedClient())
{
var binding = myWsdlClient.Endpoint.Binding as BasicHttpBinding;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
/* Client creds */
myWsdlClient.ClientCredentials.UserName.UserName = "MyClientUserName";
myWsdlClient.ClientCredentials.UserName.Password = "MyClientPassword";
/* Disable HTTPS requirement */
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
/* Proxy creds */
/*
* Since the credentials for the Proxy are in the URL,
* set the proxy credential type to None (the default value).
* Otherwise, WCF may attempt using myWsdlClient.ClientCredentials to
* authenticate with the Proxy.
*/
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
/* Note: UseDefaultWebProxy is true by default. */
binding.UseDefaultWebProxy = false;
binding.BypassProxyOnLocal = false;
/* Ensure your Proxy Server supports passing credentials in the URL. */
binding.ProxyAddress = new Uri("http://MyProxyUserName:MyProxyPassword@myproxyaddress.com:8080");
/* Send request */
myWsdlClient.Endpoint.Address = new EndpointAddress("https://myclientaddress.com");
myWsdlClient.doSomeAction(actionRequest);
}
推荐阅读
- r - 在评估表达式时解析 R 中的错误
- python - 比较特征提取器(或比较对齐的图像)
- javascript - 将 _body 内容(字符串)转换为 arrayBuffer
- php - 使用 PHP 将项目循环并计数到多维数组中
- javascript - D3js 饼图未显示在本地主机上
- python - Python 3.7.2 ModuleNotFoundError:没有名为 pysqlite2 的模块
- java - 汇总 ArrayList 中的所有条目
- c++ - int' to float' 需要缩小转换
- java - 无法使用具有多个步骤文件的 Cucumber 配置 Spring Boot
- python - 不明白 os.path.dirname() 是如何工作的