Установите CurrentPrincipal в Winforms для всех потоков - PullRequest
4 голосов
/ 04 января 2011

В приложении .NET 3.5 Winforms после того, как пользователь предоставил имя пользователя и пароль, я установил пользовательский принципал в свойстве CurrentPrincipal следующим образом:

My.User.CurrentPrincipal = Service.GetPrincipal(username)

Это делается способом, которыйвызывается с помощью Invoke, поскольку исходный поток не является потоком пользовательского интерфейса:

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

Ответы [ 2 ]

11 голосов
/ 14 марта 2013

Вместо Thread.CurrentPrincipal (My.User.CurrentPrincipal) используйте AppDomain.SetThreadPrincipal:

AppDomain.CurrentDomain.SetThreadPrincipal(principal)
6 голосов
/ 04 января 2011

Вы сражаетесь с чем-то, что называется «контекстом вызова» в .NET Framework. Мне нужно немного помахать руками, потому что я не совсем понимаю. Основная предпосылка заключается в том, что нынешний принципал - это большое дело в безопасности .NET. Это позволяет работать в песочнице, помогая изолировать код, чтобы он не делал ничего опасного. Код работает в браузере, телефоне, плагине и тому подобное.

Текущий участник связан с потоком, свойством Thread.CurrentPrincipal. Это делает Control.Begin / Invoke () хитрым, какой-то плагин может захватить права основного потока программы, используя его для запуска кода в этом потоке. Контекст вызова является контрмерой против этого. Ваш код обновляет принцип контекста вызова, а не поток. После завершения вызванного вызова, который попадает в область битов, он не возвращается обратно в исходный поток в случае Control.Invoke ().

Нахождение обходного пути для этого ошеломляет меня прямо сейчас. Это действительно должен быть код, который исходит из вашего основного потока, который устанавливает свойство, ничего, что бы не вызывалось. Я могу думать только о глупом исправлении, используя таймер на одну миллисекунду:

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

Это работает. Остерегайтесь возможной расы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...