WCF身份验证不起作用

时间:2016-11-18 21:41:52

标签: c# wcf authentication

我创建了一份服务合同

的服务
[ServiceContract]
public interface IService1
{
     [OperationContract]
     string GetData(int value);
}

使用以下自定义身份验证(不在App_Code中)

public class CustomAuthenticator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        try
        {
            if (userName.Equals("user") && password.Equals("pass"))
            {
                //Good to go
            }
        }
        catch (Exception ex)
        {
            throw new FaultException("Authentication failed");
        }
    } 
}

我的服务配置。我使用basicHttpBinding和自定义用户身份验证(我不想使用wsHttpBinding,这使得必须拥有证书)

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="myBasicBinding">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
            <transport clientCredentialType="None" proxyCredentialType="None"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service name="TestService.Service1" behaviorConfiguration="customBehavior">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="myBasicBinding" contract="TestService.IService1" />
        <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="customBehavior">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" 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="false"/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TestService.CustomAuthenticator,TestService"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
<system.webServer>

服务托管在IIS 8.5上,启用了匿名和表单身份验证。我拿了一个Console应用程序客户端,添加了服务参考和下面的配置

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService1">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
            <transport clientCredentialType="None" proxyCredentialType="None"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://techspider/Service/Service1.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
        contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
    </client>
  </system.serviceModel>

但是,当我在服务上调用一个方法时,似乎接受了任何用户名/密码,这让我觉得它不会进入我实现的自定义身份验证类。

如果我没有提供任何UserName,则会向我显示错误,表明我的设置正确无误。

   Service1Client client = new Service1Client();
    client.GetData(1);
  

未提供用户名。在ClientCredentials中指定用户名。

以下代码即使提供了错误的凭据,也能够获取输出。

Service1Client client = new Service1Client();
client.ClientCredentials.UserName.UserName = "aaaa";
client.ClientCredentials.UserName.Password = "dddd";
client.GetData(1);

如果我在服务器上缺少任何配置,有人可以建议吗?如何确保我的CustomAuthenticator在每次方法调用时都被执行。我在网上搜索了一些问题,但没有一个问题得到解决。

1 个答案:

答案 0 :(得分:1)

感觉每个用户名密码组合都被接受是正确的。情况就是这样,因为你并没有真正验证凭证。

if (userName.Equals("user") && password.Equals("pass"))
{
    //Good to go
}

如果提交了这些演示凭证,那么很高兴 ;-)但如果这不适用怎么办?如果提交了任何其他用户名密码组合,那么 nothing 就会发生!这正是您的服务接受任意凭据的原因。在catch - 块中,您将抛出信息性FaultException,但只要没有发生异常(在此简单示例中不是这种情况),它就不会被触发

如果您查看文档,则会出现very important remark和相应的代码示例:

  

重写Validate方法以指定验证用户名和密码的方式。如果用户名和密码未通过验证,则抛出SecurityTokenValidationException。

因此,如果提交的凭据不匹配,则应该抛出SecurityTokenValidationException来拒绝登录尝试。

public class CustomAuthenticator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        try
        {
            if (userName.Equals("user") && password.Equals("pass"))
            {
                //Good to go
            }
            else
            {
                // add this line
                throw new SecurityTokenException("Unknown Username or Password");
            }
        }
        catch (Exception ex)
        {
            throw new FaultException("Authentication failed");
        }
    } 
}