You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C# SOAP服务引用中设置WSS-Type(PasswordText)?

解决WPF C#调用SOAP服务时的WS-Security PasswordText认证问题

看起来你混淆了HTTP Basic认证和WS-Security UsernameToken认证——SoapUI里设置的WSS-Type=PasswordText属于后者,而你当前代码添加的是HTTP层面的Basic Auth头,这就是为什么服务返回401错误:它期望的是SOAP信封内的WS-Security安全头,而非HTTP头里的Basic认证信息。

下面给你几个针对性的解决方案:

方案1:通过WCF绑定配置启用WS-Security UsernameToken

如果你是用Service Reference引入的服务,最规范的方式是修改项目的app.config/web.config,配置绑定支持WS-Security的UsernameToken认证,并指定密码类型为明文(PasswordText)。

步骤1:修改绑定配置

把默认的绑定替换为WSHttpBinding,并配置安全规则:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="MyServiceBinding">
        <!-- 根据服务要求选择安全模式,如果是HTTPS可以用TransportWithMessageCredential -->
        <security mode="Message">
          <message 
            clientCredentialType="UserName" 
            negotiateServiceCredential="false" 
            establishSecurityContext="false" />
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
  <client>
    <endpoint 
      address="你的服务Endpoint地址"
      binding="wsHttpBinding"
      bindingConfiguration="MyServiceBinding"
      contract="MyServiceReference.IMyService"
      name="MyServiceEndpoint" />
  </client>
</system.serviceModel>

步骤2:简化代码逻辑

配置好绑定后,代码里只需要设置凭据,不需要手动添加HTTP头,同时要确保密码类型为明文:

using (var mainClient = new MyClient("MyServiceEndpoint"))
{
    mainClient.ClientCredentials.UserName.UserName = "你的用户名";
    mainClient.ClientCredentials.UserName.Password = "你的密码";
    
    // 强制指定密码类型为明文(默认可能是摘要,不符合PasswordText要求)
    var passwordTypeProp = mainClient.ClientCredentials.UserName
        .GetType()
        .GetProperty("PasswordType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    passwordTypeProp?.SetValue(mainClient.ClientCredentials.UserName, System.ServiceModel.Security.PasswordType.Text);

    var myRequestObject = ...;
    var mainResponse = mainClient.GetResponse(myRequestObject);
}

方案2:手动添加WS-Security UsernameToken头

如果配置绑定的方式不生效(比如服务的WS-Security规则比较特殊),可以通过自定义消息检查器,完全模拟SoapUI的请求格式,手动构造WS-Security Header插入到SOAP消息中。

步骤1:创建消息检查器

public class WsSecurityUsernameTokenInspector : IClientMessageInspector
{
    private readonly string _username;
    private readonly string _password;

    public WsSecurityUsernameTokenInspector(string username, string password)
    {
        _username = username;
        _password = password;
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        // 构造符合WS-Security标准的安全头
        var securityHeader = MessageHeader.CreateHeader(
            "Security",
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
            GetSecurityHeaderContent(),
            false);
        request.Headers.Add(securityHeader);
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState) { }

    private XElement GetSecurityHeaderContent()
    {
        var utcNow = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
        var nonce = Guid.NewGuid().ToString("N"); // 随机值,增强安全性

        return new XElement(
            XName.Get("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"),
            new XElement(
                XName.Get("UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"),
                new XElement(XName.Get("Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"), _username),
                new XElement(
                    XName.Get("Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"), 
                    _password,
                    new XAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText")),
                new XElement(XName.Get("Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"), 
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(nonce))),
                new XElement(XName.Get("Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"), utcNow)
            )
        );
    }
}

步骤2:创建行为扩展类

public class WsSecurityUsernameTokenBehavior : IEndpointBehavior
{
    private readonly string _username;
    private readonly string _password;

    public WsSecurityUsernameTokenBehavior(string username, string password)
    {
        _username = username;
        _password = password;
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
    public void Validate(ServiceEndpoint endpoint) { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new WsSecurityUsernameTokenInspector(_username, _password));
    }
}

步骤3:在代码中使用

using (var mainClient = new MyClient())
{
    // 添加WS-Security行为到客户端
    mainClient.Endpoint.Behaviors.Add(new WsSecurityUsernameTokenBehavior("你的用户名", "你的密码"));

    var myRequestObject = ...;
    var mainResponse = mainClient.GetResponse(myRequestObject);
}

这个方法完全复刻了SoapUI的请求格式,能精准匹配服务对WS-Security的要求。

方案3:Web Reference(ASMX)的兼容处理

如果是用Web Reference引入的服务,可以重写GetWebRequest方法来插入WS-Security Header:

public class CustomWebServiceClient : MyWebReference.MyService
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
        var request = (HttpWebRequest)base.GetWebRequest(uri);
        // 读取原始SOAP请求流,插入WS-Security Header后重新写入
        // 具体逻辑可以参考方案2中的XML构造方式
        return request;
    }
}

不过这种方式不如Service Reference灵活,优先推荐前两种方案。

关键注意事项

  • 确认服务Endpoint地址和SoapUI中使用的完全一致
  • 检查服务要求的WS-Security版本(代码中用的是2004/01版本,和SoapUI默认一致)
  • 如果是测试环境遇到证书验证错误,可以临时禁用验证:ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

内容的提问来源于stack exchange,提问作者Shiasu-sama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:32:48