(407) 需要代理身份验证 - 基本身份验证
Posted
技术标签:
【中文标题】(407) 需要代理身份验证 - 基本身份验证【英文标题】:(407) Proxy Authentication Required - Basic Authentication 【发布时间】:2021-10-10 21:19:48 【问题描述】:编辑:
在苦苦思索了很长时间之后,我发现了一个潜在的解决方案。截至今天(2021 年 10 月 19 日),System.ServiceModel.***
软件包的最新稳定版本是 4.8.1,但有 4.9.0 的候选版本似乎完全解决了我在这里遇到的问题。
我检查了 .NET WCF GitHub 源代码,发现 this release candidate(版本 4.9.0-rc1.21431.2
)正是我想要的。他们更新了HttpTransportBindingElement
以包含Proxy
property。显然它还不是稳定版本,但它仍然可以完成工作。这样,我就可以使用如下所示的方法解决原始问题:
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
-
我还尝试了使用默认 Web 代理(它有点工作)。同样,我以编程方式将其设置为:
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 不是很有经验,我只是偶然发现了“Custom bindings”的概念,这似乎很有希望,但我仍然没有发现它是否可以满足我的需求。非常感谢您对此的任何帮助!
【问题讨论】:
根据您的需要,您可以尝试过滤器吗? 【参考方案1】:欢迎来到 Stack Overflow。感谢您的详细问题。
“正确”的解决方案是使用 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);
【讨论】:
谢谢,但你是对的,正如你提到的,这不适用于生产解决方案,基本凭据未加密(我们不希望这些凭据泄露)。你会碰巧知道如何在 WCF 中使用 HTTPS 代理吗?我发现的大多数地方似乎都表明它不受 .NET Framework 的支持。 您应该可以设置“binding.Security.Mode = BasicHttpSecurityMode.Transport”或“TransportWithMessageCredential”。这将允许通过 HTTPS 进行通信。 docs.microsoft.com/en-us/dotnet/api/…以上是关于(407) 需要代理身份验证 - 基本身份验证的主要内容,如果未能解决你的问题,请参考以下文章
在需要身份验证但不返回 407 的代理后面打开 http 连接