为多个客户端使用一项服务 [英] Using one Service for Multiple Clients

查看:45
本文介绍了为多个客户端使用一项服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经建立了具有多个端点的WCF服务.目的是使用WCF服务数据库.一位用户有一个登录名,等等.

I have set up a WCF Service with multiple endpoints. The intention being to use the WCF to serve a database. One user has one log in etc.

因此,在进行了一些研究之后,我对.svc进行了如下装饰:

So after some research I decorate the .svc like so:

<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerCall, AutomaticSessionShutdown:=True,
                 ConcurrencyMode:=ConcurrencyMode.Single, IncludeExceptionDetailInFaults:=True)>

我以为InstanceContextMode为每次调用",它会在每次调用"中创建一个服务实例,这意味着它将在每次调用后触发UsernameAuthentication.不 发生.

I made thought that with the InstanceContextMode being Per Call, that it would create a Service Instance Per Call, meaning it would fire the UsernameAuthentication after each call... However after putting in a line to write to the event log, this doesn't happen.

验证:

Imports System.Data.SqlClient
Imports System.IdentityModel.Selectors
Imports System.Reflection
Imports System.Security
Imports System.Threading
Imports DVPWCFService.Modules

Namespace Classes.Admin

    Public Class Validation
        Inherits UserNamePasswordValidator

        Private _dbUsername As String
        Private _dbPassword As SecureString

        Public Overrides Sub Validate(userName As String, password As String)
            Try
                _dbUsername = userName
                _dbPassword = ConvertToSecureString(password)
                DbUsername = userName
                DbPassword = ConvertToSecureString(password)

                Dim dummyConnectionForValidation As SqlConnection = LogInTry("A real server name")

                dummyConnectionForValidation.Close()
                dummyConnectionForValidation.Dispose()

            Catch ex As Exception

                If ex.GetType Is GetType(SqlException) Then
                    DVPEventLog.WriteEntry("Authentication has failed for user: '" + userName + "'", EventLogEntryType.Warning)
                Else
                    DVPEventLog.WriteEntry("Error: " & ex.Message & Environment.NewLine & Environment.NewLine & "Stack Trace: " & ex.StackTrace & Environment.NewLine & Environment.NewLine & "Method Name: " & MethodBase.GetCurrentMethod.Name, EventLogEntryType.Error, EventLogEntryType.Error)
                End If

                Thread.Sleep(5000)

                Throw New FaultException("Log in failed.")
            End Try
        End Sub

        Private Function LogInTry(serverName As String) As SqlConnection
            LogInTry = New SqlConnection
            LogInTry.ConnectionString = "Data Source=" & serverName & ";Persist Security Info=True;MultipleActiveResultSets=True;"
            LogInTry.FireInfoMessageEventOnUserErrors = True
            LogInTry.Credential = New SqlCredential(_dbUsername, _dbPassword)
            LogInTry.Open()
        End Function

        Private Function ConvertToSecureString(convertee As String) As SecureString

            ConvertToSecureString = New SecureString()

            For Each stringCharacter In convertee.ToCharArray()
                ConvertToSecureString.AppendChar(stringCharacter)
            Next

            ConvertToSecureString.MakeReadOnly()

        End Function

    End Class
End Namespace

因此,在验证代码中,我只是确保用户可以登录到服务器.我存储用户名,以便在验证发生后可以再次使用它,因为我认为验证后它会直接转到我进行的呼叫中,而无需处理任何事情.

So in the validation code I just make sure the user can log in to the server. I store the username so I can use it again after the Validation occurs because i presumed after the validation it'd go straight to the call I made without disposing of anything.

应用配置:

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" strict="false" explicit="true" targetFramework="4.5.2" />
    <httpRuntime targetFramework="4.5.2"/>
  </system.web>
  <system.serviceModel>
    <bindings>

      <wsHttpBinding>
        <binding name="SSL Binding" openTimeout="00:00:20" receiveTimeout="08:00:00" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="2147483647"
            maxBytesPerRead="4096" maxNameTableCharCount="2147483647" />
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None" />
            <message clientCredentialType="UserName" algorithmSuite="TripleDesSha256Rsa15" />
          </security>
        </binding>
      </wsHttpBinding>

    </bindings>
    <services>

      <service behaviorConfiguration="Custom Validation Service Behavior" name="DVPWCFService.DVP">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
          name="IComponent" contract="DVPWCFService.Interfaces.IComponent" />
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
          name="IProgramme" contract="DVPWCFService.Interfaces.IProgramme" />
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
          name="IVehicle" contract="DVPWCFService.Interfaces.IVehicle" />
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
          name="IMiscellaneous" contract="DVPWCFService.Interfaces.IMiscellaneous" />
        <endpoint address="mex" binding="mexHttpsBinding" name="metadata"
          contract="IMetadataExchange" />
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="SSL Binding"
          name="IReservation" contract="DVPWCFService.Interfaces.IReservation" />
      </service>

    </services>
    <behaviors>
      <serviceBehaviors>

        <behavior name="Custom Validation Service Behavior">
          <serviceMetadata httpsGetEnabled="true" />
          <serviceDebug httpHelpPageEnabled="true" httpsHelpPageEnabled="true"
            includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <serviceCertificate findValue="blahblahblah"
              x509FindType="FindByThumbprint" />
            <userNameAuthentication userNamePasswordValidationMode="Custom"
              customUserNamePasswordValidatorType="DVPWCFService.Classes.Admin.Validation, DVPWCFService"/>
          </serviceCredentials>
          <dataContractSerializer />
          <serviceThrottling maxConcurrentCalls="10" maxConcurrentSessions="10" maxConcurrentInstances="1" />
        </behavior>

      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="wsHttpBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="false" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="false"/>
  </system.webServer>

</configuration>

当有一个以上的人使用服务时,这一切都会崩溃,因为它会覆盖用户名和密码变量.这很奇怪,因为我将其设置为每次通话和单次通话?我没有正确处理吗?有没有办法确保它得到 处理并让每个呼叫通过验证等?

This all falls apart when there's more than one person using the Service because it overwrites the Username and Password variables. This is strange as I set it to per call and single? Am I not disposing of it properly? Is there a way to make sure it gets disposed of and to make each call go through the validation etc?

推荐答案

目的是使用WCF为数据库提供服务.一位用户有一个登录名,等等.

大多数人只会在连接字符串上使用通用的用户ID和psw,因此无需在数据库级别上对用户进行身份验证.任何用户身份验证都应该在客户端端上很好地实现,甚至在后端代码均未实现之前

Most would just use a generic user-id and psw on the connectionstring so no user would need to be authenticated at the DB level. Any user authentication should be implemented on the client side well before backend code is even called. 


这篇关于为多个客户端使用一项服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆