在.NET 3.5 Winforms应用程序中,在用户提供用户名和密码后,我在CurrentPrincipal
属性中设置了一个自定义主体,如下所示:
My.User.CurrentPrincipal = Service.GetPrincipal(username)
这是在使用Invoke调用的方法中完成的,因为原始线程不是UI线程:
Invoke(New Action(AddressOf doLogin))
但是当我点击Winforms应用程序中的某个按钮时,CurrentPrincipal属性已恢复为默认值,即当前的Windows用户。
Dim lPrincipal = My.User.CurrentPrincipal ' not my custom principal
显然,在设置主体时使用Invoke并不能解决问题。是否有另一种方法为应用程序中的所有线程设置CurrentPrincipal
属性?
重现问题的源代码:
Imports System.Security.Principal
Imports System.Threading
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim lThread As New Thread(AddressOf doLogin)
lThread.Start()
End Sub
Private Sub doLogin()
Invoke(New Action(AddressOf setPrincipal))
End Sub
Private Sub setPrincipal()
My.User.CurrentPrincipal = New CustomPrincipal
MsgBox(My.User.CurrentPrincipal.Identity.AuthenticationType) ' Custom
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
MsgBox(My.User.CurrentPrincipal.Identity.AuthenticationType) ' Default
End Sub
End Class
Public Class CustomPrincipal
Implements IPrincipal
Public ReadOnly Property Identity() As IIdentity Implements IPrincipal.Identity
Get
Return New CustomIdentity()
End Get
End Property
Public Function IsInRole(ByVal role As String) As Boolean Implements IPrincipal.IsInRole
Return True
End Function
End Class
Public Class CustomIdentity
Implements IIdentity
Public ReadOnly Property AuthenticationType() As String Implements IIdentity.AuthenticationType
Get
Return "Custom"
End Get
End Property
Public ReadOnly Property IsAuthenticated() As Boolean Implements IIdentity.IsAuthenticated
Get
Return True
End Get
End Property
Public ReadOnly Property Name() As String Implements IIdentity.Name
Get
Return "CustomName"
End Get
End Property
End Class
答案 0 :(得分:11)
而不是Thread.CurrentPrincipal
(My.User.CurrentPrincipal
),请使用AppDomain.SetThreadPrincipal
:
AppDomain.CurrentDomain.SetThreadPrincipal(principal)
答案 1 :(得分:6)
你正在与.NET框架中称为“调用上下文”的东西进行斗争。我需要挥动一下手,因为我完全不了解它。基本前提是当前的主体是.NET安全的大交易。它使沙箱工作,帮助隔离代码,使其不能做任何不安全的事情。代码在浏览器,手机,插件中运行,等等。
当前主体与线程Thread.CurrentPrincipal属性相关联。这使得Control.Begin / Invoke()变得棘手,某种插件可以通过使用它在该线程上运行代码来劫持程序主线程的权限。呼叫上下文是针对此的反制措施。您的代码正在更新调用上下文的主体,而不是线程。在调用的调用完成后,它位于bit桶中,在Control.Invoke()的情况下,它不会流回原始线程。
为此找到一个解决方法让我感到困惑。它实际上必须是源自设置属性的主线程的代码,不会被调用。我只能想到一个愚蠢的修复,使用一毫秒的Timer:
Private Sub setPrincipal()
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Timer1.Enabled = False
My.User.CurrentPrincipal = New CustomPrincipal
MsgBox(My.User.CurrentPrincipal.Identity.AuthenticationType) ' Custom
End Sub
确实有效。当心可能的比赛。