如何基于指定SOAP请求创建WCF SOAP服务并配置WS-Security?
处理WS-Security的WCF服务实现方案
针对你需要接收指定SOAP请求、以字符串获取Body内容并处理WS-Security UsernameToken的需求,以下是具体实现步骤:
1. 定义服务契约与消息契约
因为要直接获取SOAP Body的原始字符串,我们使用MessageContract来包装请求,同时确保操作的Action匹配请求中的wsa:Action:
using System.ServiceModel; using System.ServiceModel.Channels; [ServiceContract(Namespace = "")] // 匹配请求中<ABC>节点的命名空间(此处无命名空间) public interface ISoapService { [OperationContract(Action = "SoapRQ")] // 严格匹配请求的wsa:Action值 string ReceiveSoapRequest(SoapRequestMessage request); } // 自定义消息契约,用于接收整个SOAP Body内容 [MessageContract] public class SoapRequestMessage { [MessageBodyMember] public string BodyContent; // 后续可自行反序列化该字符串 }
服务实现类中,还可以手动读取WS-Security Header中的用户名:
public class SoapService : ISoapService { public string ReceiveSoapRequest(SoapRequestMessage request) { // 读取WS-Security Header中的用户名 var securityHeaderIndex = OperationContext.Current.IncomingMessageHeaders.FindHeader( "Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); if (securityHeaderIndex != -1) { var reader = OperationContext.Current.IncomingMessageHeaders.GetReaderAtHeader(securityHeaderIndex); reader.ReadToDescendant("Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); string username = reader.ReadElementContentAsString(); // 此处添加用户名验证或业务逻辑 } // 处理BodyContent字符串,比如反序列化<ABC>节点 return "请求已成功接收"; } }
2. 配置WCF支持WS-Security与WS-Addressing
在配置文件(web.config/app.config)中设置绑定、行为与终结点:
绑定配置
使用wsHttpBinding原生支持WS-Security和WS-Addressing,结合HTTPS传输(对应请求中的HTTPS地址):
<system.serviceModel> <bindings> <wsHttpBinding> <binding name="SoapServiceBinding"> <security mode="TransportWithMessageCredential"> <message clientCredentialType="UserName" establishSecurityContext="false" negotiateServiceCredential="false"/> <!-- 关闭安全上下文协商,适配仅含用户名的Token --> </security> <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/> </binding> </wsHttpBinding> </bindings>
服务行为与自定义验证
由于请求中的UsernameToken仅含用户名,需自定义验证器跳过密码校验:
<behaviors> <serviceBehaviors> <behavior name="SoapServiceBehavior"> <serviceMetadata httpsGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="YourNamespace.CustomUsernameValidator, YourAssembly"/> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors>
自定义验证器实现:
using System.ServiceModel.Security; namespace YourNamespace { public class CustomUsernameValidator : UserNamePasswordValidator { public override void Validate(string userName, string password) { // 根据业务需求验证用户名,此处示例仅校验指定用户名 if (string.IsNullOrWhiteSpace(userName) || !userName.Equals("soapUserName", StringComparison.OrdinalIgnoreCase)) { throw new FaultException("无效的用户名"); } // 若无需严格校验,可直接跳过判断 } } }
终结点配置
<services> <service name="YourNamespace.SoapService" behaviorConfiguration="SoapServiceBehavior"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="SoapServiceBinding" contract="YourNamespace.ISoapService"/> <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/> </service> </services> </system.serviceModel>
3. 关键注意事项
- Action匹配:
OperationContract的Action属性必须与请求中的wsa:Action完全一致,否则WCF无法路由到对应操作。 - 命名空间一致性:服务契约的
Namespace要与请求中节点的命名空间匹配,此处请求无命名空间,故留空。 - HTTPS部署:请求目标为HTTPS地址,服务需部署在HTTPS环境下;测试环境可临时将安全模式改为
Message,但生产环境推荐TransportWithMessageCredential。 - mustUnderstand属性:请求中
soapenv:mustUnderstand="0"表示WCF无需强制处理该Header,但仍可通过OperationContext手动读取内容。
内容的提问来源于stack exchange,提问作者Dragon
相关产品推荐
相关产品推荐

