c# - WCF 身份验证 - 验证消息的安全性时出错

标签 c# wcf authentication

我在使用 clientCredentialType="UserName" 连接到我的 WCF 服务时遇到问题。

当我运行下面的代码时出现错误

FaultException: An error occurred when verifying security for the message.

当玩弄一些绑定(bind)值时,我也得到 Access is denied.

Fiddler 说没有授权 header ,我在请求中也找不到用户名或密码。

以下是我的配置的摘录:

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
    <services>
      <service name="InventoryServices.MobileAPI"  behaviorConfiguration="customBehaviour">
        <endpoint address=""
                  binding="basicHttpBinding"
                  bindingConfiguration="secureHttpBinding"
                  contract="InventoryServices.IMobileAPI"/>

        <endpoint address="mex"
                  binding="mexHttpsBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="customBehaviour">
          <serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" />
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom"
               customUserNamePasswordValidatorType="InventoryLibrary.Helpers.UserAuthentication,InventoryLibrary"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <bindings>
      <basicHttpBinding>
        <binding name="secureHttpBinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="MyRealm"/>
            <message clientCredentialType="UserName" algorithmSuite="Default"  />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>

我的用户名/密码验证器如下所示:

  public class UserAuthentication : UserNamePasswordValidator {
        public override void Validate(string userName, string password) {

            EntitiesContext db = new EntitiesContext();
            db.Logs.Add(new DomainModels.Log() {
                DateLogged = DateTime.Now,
                Message = "hit auth",
                Type = DomainModels.LogType.Info
            });
            db.SaveChanges();

            try {

                if (userName == "test" && password == "test123") {
                    Console.WriteLine("Authentic User");
                }
            }
            catch (Exception ex) {
                throw new FaultException("Unknown Username or Incorrect Password");
            }
        }
    }

我将此作为对我的服务的简单测试:

[OperationContract]
[XmlSerializerFormat]
void Test();

[PrincipalPermission(SecurityAction.Demand, Name = "test")]
public void Test() {

}

我的服务器上有一个自签名的 SSL 证书,我可以访问我的服务/元数据。

然后我在控制台应用程序中添加了一个服务引用,并尝试使用以下代码连接到该服务:

class Program {
    static void Main(string[] args) {

        Stuff.InitiateSSLTrust();

        BasicHttpBinding binding = new BasicHttpBinding();
        binding.Security.Mode = BasicHttpSecurityMode.Transport;
        binding.Security.Transport.Realm = "MyRealm";

        ServiceReference1.MobileAPIClient serviceProxy = new ServiceReference1.MobileAPIClient(binding, new EndpointAddress("https://xx.xx.xx.xx/InventoryServices.MobileApi.svc"));

        serviceProxy.ClientCredentials.UserName.UserName = "test";
        serviceProxy.ClientCredentials.UserName.Password = "test123";

        try {

            var a = serviceProxy.Login("a", "b");
        }
        catch (Exception ex) {
            var ex2 = ex;
        }
    }
}

public class Stuff {
    public static void InitiateSSLTrust() {
        try {
            //Change SSL checks so that all checks pass
            ServicePointManager.ServerCertificateValidationCallback =
                new RemoteCertificateValidationCallback(
                    delegate { return true; }
                );
        }
        catch (Exception ex) {
        }
    }
}

我检查了服务器上的事件查看器,每次请求都会出现此错误:

MessageSecurityException: Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.

最佳答案

您正在指定客户端使用 BasicHttpSecurityMode.Transport,而服务需要 BasicHttpSecurityMode.TransportWithMessageCredential。这是一个问题,因为该服务正在 SOAP 消息 header 中查找客户端凭据,而客户端不会使用以这种方式配置的绑定(bind)发送它们。

因此,这就是您所看到的用户名/密码对未出现在消息 header 中的原因。因此,事件查看器认为通信双方之间存在绑定(bind)不匹配是正确的。

同时将客户端上的 ClientCredentialType 设置为 BasicHttpMessageCredentialType.UserName 以实现 Message 级别的安全性。默认情况下,BasicHttpBinding 使用 None,这是匿名客户端。

下面是描述上述更改的代码片段:

var basicHttpBinding = new BasicHttpBinding(
                              BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType = 
                                     BasicHttpMessageCredentialType.UserName;

关于c# - WCF 身份验证 - 验证消息的安全性时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24099136/

相关文章:

c# - 命名空间的访问修饰符

c# - 返回 View 时出现 ASP.NET MVC NullReferenceException

WCF、元数据和 BIGIP - 我可以为 WSDL 项目强制使用正确的 url 吗?

asp.net - 如何与支持 ajax 的 Web 服务共享我的 asp.net 身份

ruby-on-rails - Rails 路由 : What does only: [] do here?

security - 用户对象应该存储在 JSON Web Token 中吗?

c# - 用c#连接mysql

c# - 如何在 C# 中使用 .cshtml 和其他文件类型作为字符串来构建开发人员文档

c# - 如何在 C# 中将 IList<T> 转换为 List<T>,性能良好且简洁?

node.js - OAuth2服务器: invalid or missing grant_type parameter