3

我是 WCF 的新手,我正在制作服务器/客户端应用程序,其中我需要一些用户/密码架构来维护每个客户端的一些自定义设置并记录谁访问该服务,但流量中的“安全性”通过网络并不是真正需要的,因为信息不敏感。因此,考虑到这一点,我正在寻找一种简单的方法来实现这一点,但我找不到它。

我有一些限制和条件:

  • Windows 安全性不是一个选项。
  • 我正在使用 clickonce 部署,因此所有内容都应包含在安装包中。我不知道正在下载它的用户的实际列表,所以我没有办法将一些证书分发给所有用户。
  • 此外,客户端将在 LAN 内通过多个 WAN 访问。必须满足的另一个要求是服务应该具有非常好的性能,因为每个响应都在流动大量数据,所以问题是:

消息安全性会损害性能吗?

“手动”方式是将用户名作为我公开的每个方法的参数传递,但这似乎是一个非常肮脏的解决方案。

在我看来,设计这个有很多限制,所以这就是我问这个的原因。

哪个是最简单的解决方案?

4

1 回答 1

3

首先,我们必须假设所有使用该服务的用户都以某种方式“注册”以使用该服务。因为如果它是公开的、匿名的,那么根本就没有跟踪。所以我的假设如下:

  1. 该服务托管在 Windows 服务/WinForms 中以支持 TCP 端点。-对于新版本的 IIS(>6),这不再是必需的假设
  2. 有一个像“用户名/密码”这样的组合来进行身份验证。这不在活动目录中(不选择 Windows 身份验证),但可能是 xml/database。
  3. 我们不愿意有类似的方法public int Add(string User, string Password, int A, int B)

我有一个带有 TCP 端点的服务,它执行类似的操作。我会分享的。我不认为这是最佳实践。

应用程序名称是 MYAPP

我提供了

customUserNamePasswordValidatorType="MYAPPHost.Authenticate, MYAPPHost" 

serviceCredentials > userNameAuthentication 

web.config 的部分。

MYAPPHost 是我的 Windows 服务的名称。Authenticate是从数据库进行身份验证的类。

message clientCredentialType="UserName"为 TCPBinding 设置。

我的 Windows 服务的 App.Config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
          switchValue="Off" propagateActivity="true" >
        <listeners>
          <add name="SERVICE_MONITOR" type="System.Diagnostics.XmlWriterTraceListener"
               initializeData="MYAPP_MONITOR.svclog" />
        </listeners>
      </source>      
      <source name="MYAPP_TRACE" switchValue="All" >
        <listeners>
          <add name="MYAPP_TRACE_LISTENER" type="System.Diagnostics.XmlWriterTraceListener"                                         
               initializeData="MYAPP_TRACE.svclog" />
        </listeners>
      </source>
    </sources>
    <trace autoflush="true" />
  </system.diagnostics> 

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="OverAllServiceBehavior">
          <serviceSecurityAudit 
            auditLogLocation="Application" 
            serviceAuthorizationAuditLevel="Failure" 
            messageAuthenticationAuditLevel="Failure" 
            suppressAuditFailure="true" />          
          <serviceDebug includeExceptionDetailInFaults="True" />
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
          <serviceThrottling maxConcurrentCalls="10000" maxConcurrentSessions="10000">    
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
          <serviceCredentials>
            <userNameAuthentication 
              userNamePasswordValidationMode="Custom" 
              customUserNamePasswordValidatorType="MYAPPHost.Authenticate, MYAPPHost"/>
          </serviceCredentials>         
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="OverAllEndPointBehavior" />
      </endpointBehaviors>
    </behaviors>        
    <bindings>
      <netTcpBinding>
        <binding name="ServiceTCPEndPointBinding" maxBufferSize="2147483647">    
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxNameTableCharCount="2147483647" />
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None" />
            <message clientCredentialType="UserName" algorithmSuite="TripleDes"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>        
    <services>
      <service behaviorConfiguration="OverAllServiceBehavior"
               name="MiddleWare.ServiceClasses.ServiceClass">    
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://127.0.0.1:15010/ServiceTCPEndPointMEX"/>            
          </baseAddresses>
        </host>    
        <endpoint address="net.tcp://127.0.0.1:15020/ServiceTCPEndPoint" contract="MiddleWare.ServiceContracts.IServiceContract" />           
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />    
      </service>
    </services>
  </system.serviceModel>
</configuration>

认证类:

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

namespace MYAPPHost
{
    public class Authenticate : UserNamePasswordValidator
    {
        public override void Validate(string UserName, string Password)
        {
            if (!CheckFromDB(UserName,Password))
                throw new Exception("UNAUTHORIZED ACCESS!!!");
        }
    }
}

在客户端,添加对 WCF (SR) 的引用后

SR.ServiceContractClient obj = new SR.ServiceContractClient("ServiceTCPEndPoint");
obj.ClientCredentials.UserName.UserName = "User1";
obj.ClientCredentials.UserName.Password = "Password1";
int I = obj.Add(1, 2);

如果未提供凭据,则会引发消息安全令牌错误。对于错误的凭据UNAUTHORIZED ACCESS发生。

于 2012-01-19T06:14:25.413 回答