仅当从 Class 库 (dll) 模拟时,AppPool 身份而不是当前用户
AppPool identity instead of Current User only when Impersonating from Class Library (dll)
我们有一个 class 库,其中包含我们在多个 Web 应用程序中使用的一些常用方法,但我们的 Impersonation
class 存在问题。在每个单独的应用程序中使用 LogonUser 模拟时,Environment.UserName
returns 是正在使用该应用程序的用户。但是当我们在 class 库的使用块模拟中调用它时,它 return 作为 AppPool 标识。
Returns 客户端用户名:
Declare Function LogonUser 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
If (LogonUser(Config.AdminUser, Config.AdminDomain, Config.AdminPassword, 9, 0, token) <> 0) Then
Dim newIdentity As WindowsIdentity = New WindowsIdentity(token)
Using impersonatedUser As WindowsImpersonationContext = newIdentity.Impersonate()
name = Environment.UserName
End Using
End If
Returns 应用程序池用户名:
Imports Class.Library
Using admin As New Impersonation
name = Environment.UserName
End Using
HttpContext.Current.User.Identity.Name
似乎 return 我们正在寻找的用户名,但我们不明白为什么 Environment.UserName
在服务器上时有效,但只有当它不使用我们的自定义时class 库的 dll 参考。下面是我们的模仿 class:
Public Class Impersonation : Implements IDisposable
Private impersonationContext As WindowsImpersonationContext = Nothing
Declare Auto Function LogonUser 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 RevertToSelf Lib "advapi32.dll" () As Boolean
Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal hToken As IntPtr, ByVal impersonationLevel As Integer, ByRef hNewToken As IntPtr) As Integer
Private Shared newIdentity As WindowsIdentity
Private Shared token As New IntPtr(0)
Public Sub New(Optional ByVal userName As String = "", Optional ByVal password As String = "", Optional ByVal domainName As String = Config.AdminDomain)
If userName = "" Then
userName = Config.AdminUser
End If
If password = "" Then
password = Config.AdminPassword
End If
Dim logonType As Integer = 9
impersonationContext = ImpersonateUser(userName, domainName, password, logonType)
End Sub
Private Sub Undo()
If impersonationContext IsNot Nothing Then
impersonationContext.Undo()
End If
End Sub
Private Shared Function ImpersonateUser(ByVal userName As String, ByVal domain As String, ByVal password As String, ByVal logonType As Integer) As WindowsImpersonationContext
Dim res As WindowsImpersonationContext = Nothing
Dim tempWindowsIdentity As WindowsIdentity = Nothing
Dim token As IntPtr = IntPtr.Zero
Dim tokenDuplicate As IntPtr = IntPtr.Zero
Try
If (RevertToSelf()) Then
If LogonUser(userName, domain, password, logonType, 0, token) Then
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
Return tempWindowsIdentity.Impersonate()
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Finally
If token <> IntPtr.Zero Then
CloseHandle(token)
End If
If tokenDuplicate <> IntPtr.Zero Then
CloseHandle(tokenDuplicate)
End If
End Try
Return res
End Function
Private disposedValue As Boolean = False
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
Undo()
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class
我感觉这与服务器上的 dll 文件有关,当我们使用 using 块时,Environment.UserName
从 运行 进程所在的位置获取用户名服务器。但是我不明白为什么它最初会在使用模拟的方法中创建 New WindowsIdentity()
时起作用,而不是当我们从我们的 dll 中引用它时它会起作用,因为它们都在服务器上 运行。
本质上,当我们在本地 运行 事情并尝试调试出现的问题时,HttpContext.Current.User.Identity.Name
已经成为我们的问题。我们想要,1. 出于知识目的回答为什么会发生这种情况,以及 2. 如果他们的偶数超过 HttpContext.Current.User.Identity.Name
,可能的解决方案。 (欢迎使用 VB 或 C# 回答。)
我通过在我的 class 库中创建一个新方法解决了我的问题:
Public Shared Function Current() As String
If Not HttpContext.Current.Request.IsLocal Then
Dim id As String = HttpContext.Current.User.Identity.Name
Return id.Substring(4)
Else
Return Environment.UserName
End If
End Function
如果服务器上的代码是 运行,它使用 HttpContext
来拉取 domain\username。然后我将域子字符串化(我们的域只有三个字符)。
如果是本地运行,我returnEnvironment.UserName
我通过简单地引用 class 和方法 (Employees.Current
)
在我的网络应用程序中调用这个字符串
我们有一个 class 库,其中包含我们在多个 Web 应用程序中使用的一些常用方法,但我们的 Impersonation
class 存在问题。在每个单独的应用程序中使用 LogonUser 模拟时,Environment.UserName
returns 是正在使用该应用程序的用户。但是当我们在 class 库的使用块模拟中调用它时,它 return 作为 AppPool 标识。
Returns 客户端用户名:
Declare Function LogonUser 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
If (LogonUser(Config.AdminUser, Config.AdminDomain, Config.AdminPassword, 9, 0, token) <> 0) Then
Dim newIdentity As WindowsIdentity = New WindowsIdentity(token)
Using impersonatedUser As WindowsImpersonationContext = newIdentity.Impersonate()
name = Environment.UserName
End Using
End If
Returns 应用程序池用户名:
Imports Class.Library
Using admin As New Impersonation
name = Environment.UserName
End Using
HttpContext.Current.User.Identity.Name
似乎 return 我们正在寻找的用户名,但我们不明白为什么 Environment.UserName
在服务器上时有效,但只有当它不使用我们的自定义时class 库的 dll 参考。下面是我们的模仿 class:
Public Class Impersonation : Implements IDisposable
Private impersonationContext As WindowsImpersonationContext = Nothing
Declare Auto Function LogonUser 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 RevertToSelf Lib "advapi32.dll" () As Boolean
Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal hToken As IntPtr, ByVal impersonationLevel As Integer, ByRef hNewToken As IntPtr) As Integer
Private Shared newIdentity As WindowsIdentity
Private Shared token As New IntPtr(0)
Public Sub New(Optional ByVal userName As String = "", Optional ByVal password As String = "", Optional ByVal domainName As String = Config.AdminDomain)
If userName = "" Then
userName = Config.AdminUser
End If
If password = "" Then
password = Config.AdminPassword
End If
Dim logonType As Integer = 9
impersonationContext = ImpersonateUser(userName, domainName, password, logonType)
End Sub
Private Sub Undo()
If impersonationContext IsNot Nothing Then
impersonationContext.Undo()
End If
End Sub
Private Shared Function ImpersonateUser(ByVal userName As String, ByVal domain As String, ByVal password As String, ByVal logonType As Integer) As WindowsImpersonationContext
Dim res As WindowsImpersonationContext = Nothing
Dim tempWindowsIdentity As WindowsIdentity = Nothing
Dim token As IntPtr = IntPtr.Zero
Dim tokenDuplicate As IntPtr = IntPtr.Zero
Try
If (RevertToSelf()) Then
If LogonUser(userName, domain, password, logonType, 0, token) Then
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
Return tempWindowsIdentity.Impersonate()
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Finally
If token <> IntPtr.Zero Then
CloseHandle(token)
End If
If tokenDuplicate <> IntPtr.Zero Then
CloseHandle(tokenDuplicate)
End If
End Try
Return res
End Function
Private disposedValue As Boolean = False
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
Undo()
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class
我感觉这与服务器上的 dll 文件有关,当我们使用 using 块时,Environment.UserName
从 运行 进程所在的位置获取用户名服务器。但是我不明白为什么它最初会在使用模拟的方法中创建 New WindowsIdentity()
时起作用,而不是当我们从我们的 dll 中引用它时它会起作用,因为它们都在服务器上 运行。
本质上,当我们在本地 运行 事情并尝试调试出现的问题时,HttpContext.Current.User.Identity.Name
已经成为我们的问题。我们想要,1. 出于知识目的回答为什么会发生这种情况,以及 2. 如果他们的偶数超过 HttpContext.Current.User.Identity.Name
,可能的解决方案。 (欢迎使用 VB 或 C# 回答。)
我通过在我的 class 库中创建一个新方法解决了我的问题:
Public Shared Function Current() As String
If Not HttpContext.Current.Request.IsLocal Then
Dim id As String = HttpContext.Current.User.Identity.Name
Return id.Substring(4)
Else
Return Environment.UserName
End If
End Function
如果服务器上的代码是 运行,它使用 HttpContext
来拉取 domain\username。然后我将域子字符串化(我们的域只有三个字符)。
如果是本地运行,我returnEnvironment.UserName
我通过简单地引用 class 和方法 (Employees.Current
)