脚本
客户< - 通过HTTPS - > DMZ防火墙< - 仅通过HTTP - > WCF服务
当客户端尝试连接到WCF服务时,它必须通过HTTPS(SSL)执行此操作.如果它尝试通过HTTP连接,DMZ防火墙无论如何都会将其重定向到HTTPS.
当请求到达DMZ防火墙时,它将通过非安全连接(仅限HTTP)转发到WCF服务.
我希望使用用户名和密码身份验证来保护我的服务,因此我尝试使用模式TransportWithMessageCredential和自定义UserNamePasswordValidator设置wsHttpBinding.
<system.serviceModel> <services> <service name="WcfService1.TestWcfService" behaviorConfiguration="WcfService1.TestWcfServiceBehavior"> <!-- Service Endpoints --> <endpoint address="" binding="wsHttpBinding" bindingName="wsHttpBinding_behind_firewall" contract="WcfService1.ITestWcfService"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfService1.TestWcfServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.WcfAuthenticationValidator,WcfService1"/> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> <bindings> <wsHttpBinding> <binding name="wsHttpBinding_behind_firewall"> <security mode="TransportWithMessageCredential"> <transport clientCredentialType="None" /> <message clientCredentialType="UserName" /> </security> </binding> </wsHttpBinding> </bindings> </system.serviceModel>
我的密码验证器类看起来像:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Security.Principal; using System.ServiceModel; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; namespace WcfService1 { public class WcfAuthenticationValidator : UserNamePasswordValidator { public override void Validate(string userName,string password) { if (userName == null) { throw new ArgumentNullException(nameof(userName)); } if (password == null) { throw new ArgumentNullException(nameof(password)); } //Todo: get username and password from DB and compare incoming password with one stored in DB. if (!(userName == "hello" && password == "world")) { throw new SecurityTokenException("UnkNown Username or Incorrect Password"); } } } }
要连接到此WCF服务,我的客户端代码如下所示:
TestWcfService.TestWcfServiceClient client = new TestWcfService.TestWcfServiceClient(); client.ClientCredentials.UserName.UserName = "hello"; client.ClientCredentials.UserName.Password = "world"; Console.WriteLine(client.GetData(0));
此客户端应用程序的app.config包含:
<system.serviceModel> <bindings> <wsHttpBinding> <binding name="wsHttpBinding_behind_firewall_ITestWcfService" /> </wsHttpBinding> </bindings> <client> <endpoint address="https://example.com/TestWcfService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding_behind_firewall_ITestWcfService" contract="TestWcfService.ITestWcfService" name="wsHttpBinding_behind_firewall_ITestWcfService"> <identity> <dns value="localhost" /> </identity> </endpoint> </client> </system.serviceModel>
使用wsHttpBinding的棘手部分是WCF服务期望所有传入流量都通过HTTPS.
解决方法
您可以在web.config中添加两个具有两个不同绑定配置的端点 – 一个用于http,另一个用于https.
与此类似的东西:
<bindings> <wsHttpBinding> <binding name="wsHttpsBindingConfig" > <security mode="TransportWithMessageCredential"> <transport clientCredentialType="None"> </transport> </security> </binding> <binding name="wsHttpBindingConfig" > </binding> </wsHttpBinding> </bindings> <services> <service name="WcfService1.Service1"> <endpoint name="wsHttpBinding" contract="WcfService1.IService1" binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConfig" address="" > </endpoint> <endpoint name="wsHttpsBinding" binding="wsHttpBinding" bindingName="wsHttpBinding_secure" contract="WcfService1.IService1" bindingConfiguration="wsHttpsBindingConfig" address=""> <identity> <dns value="localhost"/> </identity> </endpoint> </service>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。