2

我有一个 WCF 服务,它在以后的不确定时间代表用户排队和执行命令。我希望将 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
4

2 回答 2

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
        //...
    }

它假定您启用了 Windows 身份验证以捕获 WindowsIdentity。

此外,我不确定您如何对命令进行排队,以及稍后如何执行它们。

如果您愿意,可以使用其他授权方式替换 IsAuthorized 方法。

该服务有权执行该操作,并简单地记录正在执行的用户和命令。

如果这不太适合您的情况,请告诉我并提供更多信息,我可以修改答案。但希望这会引导你走向正确的方向

于 2013-03-07T22:58:41.837 回答
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()
于 2013-03-13T15:27:37.743 回答