如何为TransportWithMessageCredential模式的WCF端点强制元数据认证?
首先,先帮你理清你遇到的错误原因:
你尝试用basicHttpBinding作为元数据的httpsGetBinding,但这个绑定是专门处理SOAP消息的(带有Soap11信封结构),而元数据的httpsGet请求是普通的HTTP GET请求,根本不包含SOAP信封。WCF要求处理这类纯HTTP请求的绑定必须使用EnvelopeNone的消息版本,所以才抛出了那个版本不匹配的错误。
接下来给你两种可行的解决方案,你可以根据需求选择:
方案一:使用MEX端点替代HTTP GET获取元数据(推荐)
MEX(Metadata Exchange)是WCF专门设计的元数据交换SOAP端点,它支持完整的安全配置,能完美适配你的TransportWithMessageCredential安全模式,实现元数据获取的身份认证。
修改你的web.config配置步骤如下:
1. 更新服务行为,关闭HTTP GET方式的元数据暴露
先把原来的httpsGetEnabled关掉,避免未授权的元数据访问:
<behaviors> <serviceBehaviors> <behavior name="secure"> <!-- 关闭HTTP/HTTPS GET方式的元数据获取,强制通过MEX端点获取 --> <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" /> <!-- 保留你原有的其他行为配置,比如serviceDebug等 --> </behavior> </serviceBehaviors> </behaviors>
2. 添加MEX端点并配置安全绑定
创建一个和主服务安全模式一致的绑定,然后添加MEX端点:
<bindings> <basicHttpBinding> <!-- 保留你原有的服务绑定 --> <binding name="secure"> <security mode="TransportWithMessageCredential"> <message clientCredentialType="UserName" /> </security> </binding> <!-- 添加MEX专用的安全绑定,和主服务安全规则一致 --> <binding name="mexSecureBinding"> <security mode="TransportWithMessageCredential"> <message clientCredentialType="UserName" /> </security> </binding> </basicHttpBinding> </bindings> <services> <service behaviorConfiguration="secure" name="someProject.MyService"> <!-- 保留原有的业务服务端点 --> <endpoint binding="basicHttpBinding" contract="someProject.IService" bindingConfiguration="secure" /> <!-- 添加MEX元数据端点 --> <endpoint address="mex" binding="basicHttpBinding" bindingConfiguration="mexSecureBinding" contract="IMetadataExchange" /> </service> </services>
配置完成后,客户端必须通过SOAP请求访问https://your-service-url/mex,并且携带有效的UserName凭据才能获取元数据,完全符合你的安全要求。
方案二:保留HTTP GET方式(?wsdl)并添加认证
如果你一定要保留通过浏览器或HTTP GET请求?wsdl的方式获取元数据,需要使用支持纯HTTP请求的绑定(比如webHttpBinding),并配置其安全规则:
1. 添加webHttpBinding的安全配置
<bindings> <webHttpBinding> <binding name="metadataSecureBinding"> <security mode="Transport"> <!-- 使用Basic认证,因为是HTTPS传输,凭据会被加密 --> <transport clientCredentialType="Basic" /> </security> </binding> </webHttpBinding> <!-- 保留你原有的basicHttpBinding配置 --> </bindings>
2. 更新服务行为的元数据配置
<behaviors> <serviceBehaviors> <behavior name="secure"> <serviceMetadata httpsGetEnabled="true" httpsGetBinding="webHttpBinding" httpsGetBindingConfiguration="metadataSecureBinding" /> </behavior> </serviceBehaviors> </behaviors>
这种方式下,当用户访问https://your-service-url?wsdl时,会被要求输入用户名和密码(Basic认证),同时你的主服务端点依然保持TransportWithMessageCredential的安全模式。
注意:这种方式用的是HTTP Basic认证(传输层加密,依赖HTTPS),和主服务的消息层UserName认证是不同的机制,需要确保IIS允许Basic认证,但主服务所在的应用仍需保持匿名访问(因为主服务的凭据是在SOAP消息里传递的,不是IIS层面的认证)。
最后,配置完成后你可以用WCF测试客户端或浏览器访问元数据地址,确认必须输入有效凭据才能获取内容。
内容的提问来源于stack exchange,提问作者MiguelSlv

