WCF双工服务忽略自定义用户名身份验证。

3

我有一个自托管的WCF双工服务,使用NetHttpsBinding进行通信。它设置为使用自定义用户名/密码身份验证,通过UserNamePasswordValidator进行客户端身份验证,使用证书进行服务授权。连接正常,但是UserNamePasswordValidator从未被调用,因此我可以使用任何用户名和密码组合进行连接。所以我的问题是,为什么它忽略了我的UserNameValidator?

以下是服务的完整配置文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <system.serviceModel>
    <services>
      <service name="SchoolTestMaker.Service.SchoolTestMakerService">
        <endpoint address="" binding="netHttpsBinding" bindingConfiguration="netHttpsEndpointBinding" contract="SchoolTestMaker.Service.ISchoolTestMakerService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
          <serviceDebug includeExceptionDetailInFaults="True" />
          <!--<serviceAuthorization principalPermissionMode="Custom" />-->
          <serviceCredentials>
            <serviceCertificate findValue="**classified(FBI)**"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netHttpsBinding>
        <binding name="netHttpsEndpointBinding">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </netHttpsBinding>
    </bindings>
  </system.serviceModel>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

UserNamePasswordValidator:

public class SchoolTestMakerServiceUserNamePasswordValidator:UserNamePasswordValidator
    {
        IUnitOfWork unitOfWork;
        IHashGenerator hashGenerator;
        public SchoolTestMakerServiceUserNamePasswordValidator(IUnitOfWork unitOfWork,IHashGenerator hashGenerator)
        {
            this.unitOfWork = unitOfWork;
            this.hashGenerator = hashGenerator;
        }
        public override void Validate(string userName, string password)
        {
            throw new Exception();
            /*if(userName==null||password==null)
            {
                throw new ArgumentNullException();
            }
            string passwordHash = hashGenerator.GenerateHash(password);
            UserAccount userAccount = unitOfWork.Repository<UserAccount>().Get(x => x.UserName == userName && x.PasswordHash == passwordHash);
            if(userAccount==null)
            {
                throw new SecurityTokenException("Unknown Username or Incorrect Password");
            }*/
        }
    }

StartService方法:

public void StartService()
        {
            serviceHost = new UnityServiceHost(container,
                typeof(SchoolTestMakerService), new Uri(endpointAddress));

            //Console.WriteLine(((WSDualHttpBinding)serviceHost.Description.Endpoints[0].Binding).Security.Message.ClientCredentialType);

            serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
            serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = userNamePasswordValidator;

            /*var externalAuthorizationPolicies = new ReadOnlyCollection<IAuthorizationPolicy>(new IAuthorizationPolicy[] { authorizationPolicy });
            ServiceAuthorizationBehavior authorizationBehavior=serviceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
            authorizationBehavior.ExternalAuthorizationPolicies = externalAuthorizationPolicies;*/

            serviceHost.Open();
            ServiceRunning = true;
        }

如果链接的 SO 是真的,那么您将无法使用 CustomUsername Auth。 - TGlatzer
有什么我可以做的吗?因为我肯定想避免传递明文凭据。有支持双工和SSL的绑定吗?也许是自定义绑定? - Phoenix
我认为netTCPbindings将支持双工和传输安全:http://msdn.microsoft.com/en-us/library/ms731092(v=vs.110).aspx - TGlatzer
netTCPBinding的问题在于您需要在客户端上打开端口。昨天我从您发送的链接中了解到了netHTTPBinding。它支持Duplex、传输和消息安全性,并且使用WebSockets进行通信,这意味着我不需要在客户端上打开端口,因为它在两个方向上都使用端口80/443进行通信。我可能会使用它,但是当我从wsHTTP切换到netHTTP时,我在Visual Studio中遇到了一些添加服务引用的问题。 - Phoenix
也许您可以从另一个绑定中添加它并更改app.config文件? - TGlatzer
显示剩余6条评论
1个回答

0

如果您想使用自定义的UserNamePassword验证,您需要告诉WCF哪个类将处理验证:

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceCredentials>
          <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUsernamePasswordAuth.Service.UserNamePassValidator, CustomUsernamePasswordAuth.Service" />
        </serviceCredentials>
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

抱歉,我忘记提及一些重要的细节。我现在已经更新了问题。 - Phoenix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接