5

因此,我基本上已经使用 wsHttpBindings 和我的 WCF 服务通过 HTTPS 使用自定义身份验证来启动和运行所有内容。

我遇到的问题是 customUserNamePasswordValidatorType:

  <serviceCredentials>
    <!-- Use our own custom validation -->
    <userNameAuthentication userNamePasswordValidationMode="Custom"
                            customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
  </serviceCredentials>

按照此处找到的说明,我还创建了自定义类:

namespace CustomValidator
{
    public class CustomUserNameValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (null == userName || null == password)
            {
                throw new ArgumentNullException();
            }


            if (!AuthenticateUser(userName, password))
                throw new SecurityTokenValidationException("Invalid Credentials");

错误是“无法加载文件或程序集'CustomValidator'或其依赖项之一。系统找不到指定的文件。 ”,并指的是customUserNamePasswordValidatorType的尾部 - “...,CustomValidator”。

我不认为将自定义验证器放在自己的命名空间和类中是个问题,但我看不出还有什么可以做的。

我已经尝试过在开始时使用/不使用命名空间、交换等 - 什么都没有。

希望另一双眼睛能分辨出来。

谢谢。

编辑 system.serviceModel

  <system.serviceModel>
    <bindings>

      <!-- wsHttpBinding -->
      <wsHttpBinding>
        <binding name="wsHttpEndpointBinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None" />
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>

      <!-- webHttpBinding -->
      <webHttpBinding>
        <binding name="wsHttps" >
          <security mode="Transport"/>
        </binding>
      </webHttpBinding>

      <!-- Basic binding -->
      <basicHttpBinding>
        <binding name="TransportSecurity">
          <security mode="Transport">
            <message clientCredentialType="UserName"/>
            <!-- transport clientCredentialType="None"/-->
          </security>
        </binding>
      </basicHttpBinding>

      <!-- customBinding>
        <binding name="WebHttpBinding_IService">
          textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
              messageVersion="Soap12" writeEncoding="utf-8">
            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          </textMessageEncoding>
          <httpsTransport manualAddressing="false"/>
        </binding>
      </customBinding -->
      <!-- Another custom binding -->
      <customBinding>
        <binding name="CustomMapper">
          <webMessageEncoding  webContentTypeMapperType=
                 "IndexingService.CustomContentTypeMapper, IndexingService" />
          <httpTransport manualAddressing="true" />
        </binding>
      </customBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="Service">




        <!-- Service Endpoints -->
        <!-- since we're hosting in IIS, baseAddress is not required 
        <host>
          <baseAddresses>
            <add baseAddress="https://mysslserver.com/Service.svc"/>
          </baseAddresses>
        </host>
        -->
        <endpoint address="https://mysslserver.com/Service.svc"
                  binding="wsHttpBinding"
                  bindingConfiguration="wsHttpEndpointBinding" 
                  contract="IService"
                  name="wsHttpEndpoint">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <!--identity>
            <dns value="https://mysslserver.com"/>
          </identity-->
        </endpoint>

        <!-- endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/ -->
      </service>
    </services>
    <behaviors>

      <endpointBehaviors>
        <behavior name="webBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>

      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <!-- Setup Security/Error Auditing -->
          <serviceSecurityAudit auditLogLocation="Application"
                suppressAuditFailure="false"
                serviceAuthorizationAuditLevel="Failure"
                messageAuthenticationAuditLevel="Failure" />

          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"
                           httpsGetUrl="https://mysslserver.com/Service.svc"/>
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceCredentials>
            <!-- Use our own custom validation -->
            <userNameAuthentication userNamePasswordValidationMode="Custom"
                                    customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>

      <!-- serviceBehaviors>
        <behavior name="ServiceBehavior">
        <serviceMetadata httpsGetEnabled="true" 
                           httpsGetUrl="https://mysslserver.com/Service.svc" />
          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"/>
        </behavior-->
    </behaviors>
  </system.serviceModel>
4

4 回答 4

15

我决定再试一次,并且不喜欢将我的自定义验证器放在另一个库中。

所以我在 App_Code 中创建了一个新类,然后开始使用它......

以下是实际修复的内容,

="CustomValidator.CustomUserNameValidator, App_Code"
于 2009-12-12T00:46:14.857 回答
10

当您使用值引用自定义验证器时

="CustomValidator.CustomUserNameValidator, CustomValidator"

第一个值是类型名称,第二个值是要在其中查找类型的程序集的名称。因此,我建议在您的第一个实例中,您的服务实际上位于其他程序集中,例如 MyService 在这种情况下,您确实需要配置文件来说明

="CustomValidator.CustomUserNameValidator, MyService"

我怀疑当您为验证器创建新的类库时,您已经调用了您的项目 CustomValidator(它将输出一个名为 CustomValidator.dll 的程序集),因此现在您的配置将起作用(即它与在一个单独的类库 - 碰巧你在 web.config 中的程序集引用的命名现在是有效的)

于 2009-11-27T02:48:43.717 回答
2

看起来有点奇怪,但解决方案是创建一个单独的类库并在我的 WCF 服务中引用它的 DLL。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.ServiceModel;

/// <summary>
/// Summary description for CustomUsernamePasswordValidator
/// </summary>
namespace CustomValidator
{
    public class CustomUserNameValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (null == userName || null == password)
            {
                throw new ArgumentNullException();
            }


            if (!AuthenticateUser(userName, password))
                throw new SecurityTokenValidationException("Invalid Credentials");
            else
            {
                // do nothing - they're good
            }
        }

        public bool AuthenticateUser(string userName, string password)
        {
            if (userName != "userbill" || password != "passwordbill")
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}

然后我添加了对 System.IdentityModel 和 System.ServiceModel 的引用。

WCF 服务的 serviceCredentials 部分现在更改为:

<serviceCredentials>
    <!-- Use our own custom validation -->
    <userNameAuthentication userNamePasswordValidationMode="Custom"
                            customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
</serviceCredentials>

希望对某人有所帮助。

我尝试使用无效凭据进行此操作,并希望看到我的“无效凭据”消息。相反,我收到“无法验证消息中的至少一个安全令牌”。

除此之外,这件事终于启动并运行了!

于 2009-11-26T22:28:32.587 回答
0

只是阅读这篇文章,因为它对我必须快速开始的 POC 很有帮助。作为对上述ELHaix的回应……这应该可以确保将您的描述性自定义错误返回给客户端:

using System.ServiceModel
...    
throw new FaultException("Invalid Credentials - Custom Error");
于 2017-02-04T00:37:24.257 回答