2013-03-06 45 views
2

我有一個WCF服務,它在以後的不確定時間代表用戶排隊並執行命令。我希望將WindowsIdentity存儲爲字節數組並將其填充到數據庫中,然後反序列化並使用該對象。如何存儲WindowsIdentity以便在以後不確定的時間使用

某些時候,服務按預期執行:它正確地序列化,存儲,反序列化並以用戶身份執行命令。其他時候,當反序列化WindowsIdentity時,出現「調用目標引發異常」的錯誤,還有一些時候反序列化可行,但通過命令執行的一部分,標識不再有效。

我的問題是這樣的:是否有可能在.NET 4.0框架中使用WCF代表用戶在以後不確定的時間執行命令,而沒有明確的用戶名和密碼?

,我正在使用的代碼如下:

連載:

''' <summary> 
''' Serializes a WindowsIdentity as a binary encoded byte array. 
''' </summary> 
''' <param name="identity">The identity to serialize.</param> 
''' <returns>A byte array containing a binary representation of the identity.</returns> 
Private Function SerializeWindowsIdentity(ByVal identity As WindowsIdentity) As Byte() 
    If IsNothing(identity) Then Return Nothing 
    Try 
     Dim bf As New BinaryFormatter 
     Using ms As New MemoryStream() 
      bf.Serialize(ms, identity) 
      Return ms.ToArray() 
     End Using 
    Catch ex As Exception 
     Return Nothing 
    End Try 
End Function ' SerializeWindowsIdentity 

反序列化:

''' <summary> 
''' Deserializes a WindowsIdentity from a binary encoded byte array. 
''' </summary> 
''' <param name="identity">A byte array containing a binary representation of a WindowsIdentity</param> 
''' <returns>The deserialized WindowsIdentity from the byte array.</returns> 
Private Function DeserializeWindowsIdentity(ByVal identity As Byte()) As WindowsIdentity 
    If IsNothing(identity) OrElse identity.Count = 0 Then Return Nothing 
    Try 
     Dim bf As New BinaryFormatter() 
     Using ms As New MemoryStream(identity) 
      Dim obj As Object = bf.Deserialize(ms) 
      Return CType(obj, WindowsIdentity) 
     End Using 
    Catch ex As Exception 
     Return Nothing 
    End Try 
End Function ' DeserializeWindowsIdentity 

的WindowsIdentity捕獲:

identity = SerializeWindowsIdentity(ServiceSecurityContext.Current.WindowsIdentity) 

用法:

Dim cxt As WindowsImpersonationContext 
Try 
    Dim wi As WindowsIdentity = DeserializeWindowsIdentity(identity) 
    If Not IsNothing(wi) Then cxt = wi.Impersonate() 

    ' Do Stuff 
Finally 
    If Not IsNothing(cxt) Then cxt.Dispose() 
End If 
+0

你怎麼能期望windows身份在不確定的時間後有效?即如果用戶更改密碼,或被刪除等 – EdmundYeung99 2013-03-07 01:16:45

+0

也許如果你解釋你的用例,我們可以建議一種替代方法? – EdmundYeung99 2013-03-07 01:20:13

+0

感謝您的評論。不,我不希望在密碼更改或帳戶刪除的情況下該身份有效。 – dthagard 2013-03-07 18:45:16

回答

0

因此,我們迄今爲止的最佳解決方案是使用ServiceSecurityContext.Current.WindowsIdentity中的令牌並創建一個新的主令牌,以便我們爲以後序列化並存儲。缺點是一旦服務重新啓動,令牌就無效,但這是一個很好的臨時解決方法,直到我們可以修改我們的服務,以便我們不需要用戶的持續授權。我們看着使用S4U2Proxy哪個做我們想做的事情,但配置服務運行的域帳戶的要求對我們的用戶有點繁重。工作代碼片段如下(注意:我們可能不需要再序列化,但更容易保留,因爲我們不必更新數據庫模式。此外,我們可以從令牌重複打出來的連載程序以使代碼更易於管理):

反序列化代碼:

''' <summary> 
''' Deserializes a user token from a binary encoded byte array. 
''' </summary> 
''' <param name="identity">A byte array containing an binary representation of a user token.</param> 
''' <returns>The deserialized user token from the byte array.</returns> 
Private Function DeserializeWindowsIdentityToken(ByVal identity As Byte()) As IntPtr 
    If IsNothing(identity) Then Return Nothing 
    Dim stream As New MemoryStream(identity) 
    Dim serializer As New BinaryFormatter() 
    Try 
     Dim obj As Object = serializer.Deserialize(stream) 
     Return CType(obj, IntPtr) 
    Catch ex As Exception 
     Return IntPtr.Zero 
    End Try 
End Function ' DeserializeWindowsIdentityToken 

序列化代碼:

''' <summary> 
''' Serializes a user token as a binary encoded byte array. 
''' </summary> 
''' <param name="identity">The token to serialize.</param> 
''' <returns>A byte array containing a binary representation of the token.</returns> 
Private Function SerializeWindowsIdentityToken(ByVal identity As IntPtr) As Byte() 
    Try 
     Dim newToken As IntPtr = IntPtr.Zero 
     Const securityDelegation As Int16 = 3 
     Const tokenPrimary As Integer = 1 
     Const maximumAllowed As Integer = &H2000000 

     Dim sa As New SecurityAttributes() 
     sa.bInheritHandle = True 
     sa.Length = Marshal.SizeOf(sa) 
     sa.lpSecurityDescriptor = IntPtr.Zero 

     If DuplicateTokenEx(identity, maximumAllowed, sa, securityDelegation, tokenPrimary, newToken) = 0 Then Return Nothing 

     Dim streamWriter As New MemoryStream() 
     Dim serializer As New BinaryFormatter 
     serializer.Serialize(streamWriter, newToken) 
     Return streamWriter.ToArray() 
    Catch ex As Exception 
     Return Nothing 
    End Try 
End Function ' SerializeWindowsIdentityToken 

<StructLayout(LayoutKind.Sequential)> 
Private Structure SecurityAttributes 
    Public Length As Integer 
    Public lpSecurityDescriptor As IntPtr 
    Public bInheritHandle As Boolean 
End Structure ' SecurityAttributes 

<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> 
Private Shared Function DuplicateTokenEx(ByVal existingTokenHandle As IntPtr, 
             ByVal desiredAccess As UInteger, 
             ByRef threadAttributes As SecurityAttributes, 
             ByVal impersonationLevel As Integer, 
             ByVal tokenType As Integer, 
             ByRef duplicateTokenHandle As IntPtr) As Integer 
End Function ' DuplicateTokenEx 

令牌捕獲:

Dim storedToken As Byte() = SerializeWindowsIdentityToken(ServiceSecurityContext.Current.WindowsIdentity.Token) 

用法:

Dim identity As IntPtr = DeserializeWindowsIdentityToken(storedToken) 
Dim cxt As WindowsImpersonationContext = Nothing 
If Not IsNothing(identity) AndAlso identity <> IntPtr.Zero Then 
    Try 
     Dim identity As New WindowsIdentity(identity) 
     cxt = identity.Impersonate() 
    Catch ex As Exception 
     ' Perform error handling 
    End Try 
End If 

' Perform operations 

If Not IsNothing(cxt) Then cxt.Dispose() 
0

下面是一些僞代碼:

//When command comes in from the user, queue the work 
    private void QueueWork() 
    { 
     //Authorization Check 
     if (IsAuthorized(DoWork, ServiceSecurityContext.Current.WindowsIdentity)) 
      throw new SecurityAccessDeniedException("Unauthorized"); 

     //Queue the work for later 
     Queue.Enqueue(ServiceSecurityContext.Current.WindowsIdentity.Name); 
    } 

    //check if 
    private bool IsAuthorized(Action doWork, WindowsIdentity windowsIdentity) 
    { 
     //custom logic 
    } 

    //Command executed at a later point in time 
    private void DoWork() 
    { 
     var user = Queue.Dequeue() as string; 

     Log(user + " is invoking DoWork"); 

     //Perform command on behalf of user 
     //... 
    } 

它假定您已經啓用了捕獲的WindowsIdentity Windows身份驗證。

另外我不知道你是如何排隊的命令,以及你以後如何執行它們。

如果您願意,您可以用某種其他授權方式替換IsAuthorized方法。

該服務有權執行該操作,並簡單地記錄正在執行的用戶和命令。

如果這不符合您的情況,請告訴我並提供更多信息,我可以修改答案。但是,希望這會使您走向正確的方向

+0

感謝您的回覆。我對代表用戶的部分'//執行命令'有些迷惑。這似乎就是我無法弄清楚的魔法所在。現在我使用WindowsIdentity來執行模擬(即代表用戶操作)。如果我不存儲該WindowsIdentity,我還能如何替他們執行操作? – dthagard 2013-03-08 13:00:41

相關問題