【问题标题】:Disable CustomUserNamePasswordValidator for specific operation为特定操作禁用 CustomUserNamePasswordValidator
【发布时间】:2014-11-10 10:30:13
【问题描述】:

我正在为我的 WCF Web 服务使用 CustomUserNamePasswordValidator。但是,我正在尝试添加一个 IsAlive 操作,即使未经过身份验证,它也应该能够从客户端调用。

例如,我希望能够检查服务是否在线并且在启动时可访问,因此我可以在缺少 inet 连接或服务不可用(由于维护)时通知用户。

我已经有了所有这些的代码。我缺少的是如何在不传递用户名和密码的情况下访问操作。

我可能只添加第二个允许匿名访问的服务,但我真的更喜欢使用现有服务。

Validator 是这样实现的(我省略了实际的检查代码):

public sealed class MyCredentialValidator : UserNamePasswordValidator
{
    public MyCredentialValidator ()
    {

    }

    public override void Validate(string userName, string password)
    {
        Debug.WriteLine("MyCredentialValidator : Validate called.");

        // do some checks
        var isValid = CheckCredentials(userName, password)

        if(!isValid)
        {
            throw new FaultException(...);
        }
    }
}

它是这样在 web.config 中注册的:

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="SecureBehavior">
                <serviceMetadata httpsGetEnabled="false"/>
                <serviceDebug includeExceptionDetailInFaults="true"/>
                <serviceCredentials>
                    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyCredentialValidator,..."/>
                </serviceCredentials>
            </behavior>
        </serviceBehaviors>         
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
    <bindings>
        <wsHttpBinding>
            <binding name="SecureBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
                <security mode="TransportWithMessageCredential">
                    <message clientCredentialType="UserName"/>
                </security>
                <readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxStringContentLength="2147483647"/>
            </binding>
        </wsHttpBinding>
    </bindings>
    <services>
        <service name="my service" behaviorConfiguration="SecureBehavior">
            <endpoint address="" binding="wsHttpBinding" contract="my contract" bindingConfiguration="SecureBinding">
                <identity>
                    <dns value="localhost"/>
                </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
        </service>
    </services>
</system.serviceModel>

客户端配置:

<system.serviceModel>
<bindings>

    <wsHttpBinding>
        <binding name="SecureBinding"
                 closeTimeout="00:10:00"
                 openTimeout="00:10:00"
                 receiveTimeout="00:10:00"
                 sendTimeout="00:10:00"
                 maxReceivedMessageSize="2147483647">
            <security mode="TransportWithMessageCredential">
                <message clientCredentialType="UserName"/>
            </security>
            <readerQuotas maxArrayLength="2147483647"
                          maxBytesPerRead="2147483647"
                          maxStringContentLength="2147483647"/>
        </binding>
    </wsHttpBinding>

</bindings>

<client>

    <endpoint address="https://my service url"
              contract="my contract"
              binding="wsHttpBinding"
              bindingConfiguration="SecureBinding"
              name="secure" />
</client>

</system.serviceModel>

客户端 wcf 调用代码:

var cf = new ChannelFactory<my contract>("secure");
using (IClientChannel channel = (IClientChannel)cf.CreateChannel())
{
    channel.OperationTimeout = TimeSpan.FromSeconds(3);
    bool success = false;
    try
    {
        channel.Open();
        result = ((my contract)channel).IsAlive();
        channel.Close();
        success = true;
    }
    finally
    {
        if (!success)
        {
            channel.Abort();
        }
    }
}

【问题讨论】:

  • 好东西,虽然我不明白你为什么要实现身份验证客户端,在那里你有 debug.writeline,你应该在那里检查请求的去向,例如包含 IsAlive 然后返回,因此例如将其包装在 if else 语句中。
  • 身份验证是服务器端!需要客户端中的绑定配置,以便 wcf 知道如何构建正确且有效的请求。身份验证当然是服务器端! :) 但是,请注意异常发生在客户端,当我解析通道工厂时,建立一个新通道并调用“打开”。我在问题中添加了客户端 wcf 代码。
  • 哈哈,完美,你让我在那里呆了一秒钟,我只看到了 CheckCredentials。因此,在您开始调用 CheckCredentials 之前,您要检查您的传出 url,而不是我之前建议的传入 url,然后如果传出 url 例如包含“IsAlive”,您可以在该点简单地调用 return 而不是继续其余的检查凭据等等
  • 我愿意!但是,服务器永远不会被击中(我需要它被击中,因为我想知道它是否“还活着”)。原因是我的绑定、客户端和服务器端需要设置凭据。我当然可以用虚拟值填充它,但这似乎是“一起被黑”
  • 这意味着您需要在服务器端和客户端实现相同或相当相似的逻辑,当然假设您正在编写两者。因此,在客户端验证器中,您将检查传出请求是否要进行 Isalive 操作,如果是,则返回并且不继续其余的身份验证逻辑,然后在服务器端,如前所述检查,如果传入的请求将进入 IsAlive 操作并再次简单地返回,不执行其余的身份验证逻辑

标签: wcf c#-4.0


【解决方案1】:

我以前做过类似的事情, 取决于您如何将自定义验证器集成到 wcf 管道中, 您可以在进行实际验证之前(我猜它会返回真或假),您可以检查传入的 url 或地址,看看它是否会进入您的 IsAlive 操作,如果是这样,您可以只需提前返回 true。

Wcf 有几种方法可以用来检查客户端调用了什么操作。

更准确地说,我需要知道您是如何编写自定义验证器的,以及它集成在管道中的哪个位置。

【讨论】:

  • Validator 在 web.config 中注册为 serviceBehavior。每次服务调用都会调用它。
  • 听起来不错,您可以将这篇帖子 stackoverflow.com/questions/9110397/… 视为如何检查原始请求 url 的一个示例。您可以简单地检查它是否正在前往您的 IsAlive 操作,如果是,则返回 true,因为该方法当然不需要任何身份验证,并且很可能会返回简单的东西,例如 true 或 false
  • 有几种方法,我只是选择了上面的一种,因为它已经在堆栈溢出了。如果它不适合您,请告诉我,我会帮助您找到解决方法
  • 感谢您的建议,但是我在客户端遇到了异常,因为我没有提供调用“IsAlive”的凭据。似乎它明确要求设置凭据,以便可以进行任何调用。
  • 你能分享你的自定义验证器吗,我们将不得不在其中进行更改。这将是您的服务器导致异常,因为我想自定义验证器驻留在服务器端,并且您的客户端只是在进行调用,该调用被自定义验证器服务器端拦截,该服务器端看到没有凭据已经提供或类似的东西。在我的建议中,应该驻留在您的自定义验证器中的第一个代码将是检查是否请求 IsAlive 操作。
猜你喜欢
  • 1970-01-01
  • 2015-08-11
  • 1970-01-01
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多