簡體   English   中英

有沒有一種方法可以使用網絡服務帳戶將Windows C#應用程序連接到SQL Server

[英]Is there a way to connect Windows C# Application to SQL Server using a Network Service Account

我有一個C#應用程序,該應用程序使用AD組進行身份驗證來訪問SQL Server數據庫,但是有人告訴我他們希望將其切換為使用與當前通過Web服務器應用程序池使用的Web應用程序相同的網絡服務帳戶。 由於Windows應用程序不經過Web服務器和應用程序池,因此我不確定如何將Windows應用程序配置為使用與Web應用程序相同的網絡服務帳戶。 我已經搜索過SO,MSDN和Google,但一無所獲。 有沒有辦法做到這一點? 謝謝你的幫助。

您將需要使用模擬。 我們在Web應用程序中使用一個自定義類使用它:

Imports System.Web
Imports System.Web.Security
Imports System.Security.Principal
Imports System.Runtime.InteropServices

''' <summary>Creates an impersonation session if needed</summary>
''' <remarks>
'''        This is a clever little object, it is designed to facilitate the 'using' functionality to handle the initialisation and disposal of the impersonation
'''        context.  It will only impersonate if the connection is set up to use windows authentication otherwise it will do nothing
'''
'''        Recommended usage
'''            using new impersonate(domain, username, password)
'''                Do database Stuff
'''            end using
'''    </remarks>
Public Class Impersonate
    Implements IDisposable


Private isImpersonating As Boolean = False

Private Sub Impersonate(ByVal domain As String, ByVal username As String, ByVal password As String)
    If Me.impersonateValidUser(username, domain, password) Then
        ' all is well
    Else
        ' not so well, raise exception
        Throw New System.Exception("Unable to use provided AD authentication to connect to database")
    End If
End Sub

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' clean up the impersonation
                undoImpersonation()
            End If

        End If
        Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region



#Region "Impersonate"

Dim LOGON32_LOGON_INTERACTIVE As Integer = 2
Dim LOGON32_PROVIDER_DEFAULT As Integer = 0

Dim impersonationContext As WindowsImpersonationContext

Declare Function LogonUserA Lib "advapi32.dll" (ByVal lpszUsername As String, _
                        ByVal lpszDomain As String, _
                        ByVal lpszPassword As String, _
                        ByVal dwLogonType As Integer, _
                        ByVal dwLogonProvider As Integer, _
                        ByRef phToken As IntPtr) As Integer

Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
                        ByVal ExistingTokenHandle As IntPtr, _
                        ByVal ImpersonationLevel As Integer, _
                        ByRef DuplicateTokenHandle As IntPtr) As Integer

Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long


Public Sub Page_Loada(ByVal s As Object, ByVal e As EventArgs)
    If impersonateValidUser("username", "domain", "password") Then
        'Insert your code that runs under the security context of a specific user here.
        undoImpersonation()
    Else
        'Your impersonation failed. Therefore, include a fail-safe mechanism here.
    End If
End Sub

Private Function impersonateValidUser(ByVal userName As String, _
ByVal domain As String, ByVal password As String) As Boolean

    Dim tempWindowsIdentity As WindowsIdentity
    Dim token As IntPtr = IntPtr.Zero
    Dim tokenDuplicate As IntPtr = IntPtr.Zero
    impersonateValidUser = False

    If CType(RevertToSelf(), Boolean) Then
        If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                     LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
            If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
                impersonationContext = tempWindowsIdentity.Impersonate()
                If Not impersonationContext Is Nothing Then
                    impersonateValidUser = True
                End If
            End If
        End If
    End If
    If Not tokenDuplicate.Equals(IntPtr.Zero) Then
        CloseHandle(tokenDuplicate)
    End If
    If Not token.Equals(IntPtr.Zero) Then
        CloseHandle(token)
    End If
End Function

Private Sub undoImpersonation()
    If Me.isImpersonating Then
        impersonationContext.Undo()
    End If
End Sub

#End Region
End Class

然后,您可以使用以下代碼調用該類:

using new impersonate(domain, username, password)
   ' Do database Stuff
end using

我認為以網絡服務連接到SQL的唯一方法是將應用程序作為網絡服務運行(我認為模擬不適用於該帳戶)。 假設我們正在談論客戶端應用程序(控制台,Windows Forms或WPF),我看到3個選項:

  1. 使用PsExec.exe Sysinternals公司的描述來運行你的應用程序作為網絡服務在這里
  2. 將您的應用程序分為兩部分-Windows服務實現數據訪問並作為網絡服務運行,客戶端應用程序與該服務通信並實現UI和應用程序層
  3. 將數據訪問實現為Web服務,以便它可以在網絡服務憑據下的應用程序池中運行,並使您的應用程序使用該Web服務來訪問數據。 我認為這種方式在大多數情況下是可取的,但可能需要進行認真的重構。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM