2008-11-03 5 views
20

En C#, comment définir l'identité d'un thread? Par exemple, si Thread MyThread est déjà démarré, est-ce que je peux changer l'identité de MyThread?Définir l'identité du thread

Ou est-ce impossible?

Répondre

27

Vous pouvez définir l'identité d'un thread en créant un nouveau principal. Vous pouvez utiliser n'importe quelle identité qui hérite de System.Security.Principal.IIdentity, mais vous avez besoin d'une classe qui hérite de System.Security.Principal.IPrincipal qui prend le type d'identité que vous utilisez.
Par souci de simplicité, le framework .Net fournit GenericPrincipal et GenericIdentity classes qui peuvent être utilisés comme ceci:

using System.Security.Principal; 

// ... 
GenericIdentity identity = new GenericIdentity("M.Brown"); 
identity.IsAuthenticated = true; 

// ... 
System.Threading.Thread.CurrentPrincipal = 
    new GenericPrincipal(
     identity, 
     new string[] { "Role1", "Roll2" } 
    ); 

//... 
if (!System.Threading.Thread.CurrentPrincipal.IsInRole("Roll1")) 
{ 
     Console.WriteLine("Permission denied"); 
     return; 
} 

Ce ne sera toutefois pas vous donner droit à des choses de Windows en utilisant la nouvelle identité. Mais cela peut être utile si vous développez un site Web et souhaitez créer votre propre gestion des utilisateurs.

Si vous voulez prétendre être un utilisateur Windows différent du compte que vous utilisez actuellement, vous devez utiliser l'emprunt d'identité. Un exemple de la façon de le faire peut être trouvé dans l'aide pour System.Security.Principal.WindowsIdentity.Impersonate(). Il existe des limitations concernant les comptes dans lesquels le compte que vous utilisez peut usurper l'identité.

Dans certains cas, l'infrastructure .Net fait l'usurpation d'identité pour vous. Un exemple de cette situation se produit si vous développez un site Web ASP.Net et que l'authentification Windows intégrée est activée pour le répertoire ou le site virtuel dans lequel vous exécutez.

+0

Si vous utilisez ['GenericIdentity Constructor (String, String)'] (http: // msdn. microsoft.com/en-us/library/2wh03ckb(v=vs.110).aspx) vous pouvez ignorer le bit 'IsAuthenticated = true'. –

+0

J'utilise .NET 4.5, et je ne peux pas compiler cette déclaration identity.IsAuthenticated = true; parce que la propriété "IsAuthenticated" a seulement l'accesseur, pouvez-vous s'il vous plaît, faire une mise à jour pour le code dans lequel l'utilisation de framework .NET 4.5.merci de toute façon, votre code m'a aidé, (avec quelques modifications) –

+1

J'ai modifié votre code dans .NET 4.5 comme suit pour le faire fonctionner GenericIdentity identity = new GenericIdentity ("user1", "Forms"); Thread.CurrentPrincipal = new GénériquePrincipal (identité, nouvelle chaîne [] {"rôle1"}); vous pourriez utiliser ce code pour mettre à jour votre poste utile, merci encore. –

3

Oui, en utilisant impersonation littéralement

using (new Impersonation()) 
{ 
    // your elevated code 
} 

et la classe est la suivante, pour les réglages que j'utilise le dictionnaire adaptateur du château s'il semble étrange.

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
public class Impersonation : IDisposable 
{ 
    private readonly SafeTokenHandle _handle; 
    private readonly WindowsImpersonationContext _context; 

    //const int Logon32LogonNewCredentials = 9; 
    private const int Logon32LogonInteractive = 2; 

    public Impersonation() 
    { 
     var settings = Settings.Instance.Whatever; 
     var domain = settings.Domain; 
     var username = settings.User; 
     var password = settings.Password; 
     var ok = LogonUser(username, domain, password, Logon32LogonInteractive, 0, out _handle); 
     if (!ok) 
     { 
      var errorCode = Marshal.GetLastWin32Error(); 
      throw new ApplicationException(string.Format("Could not impersonate the elevated user. LogonUser returned error code {0}.", errorCode)); 
     } 
     _context = WindowsIdentity.Impersonate(_handle.DangerousGetHandle()); 
    } 

    public void Dispose() 
    { 
     _context.Dispose(); 
     _handle.Dispose(); 
    } 

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); 

    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid 
    { 
     private SafeTokenHandle() 
      : base(true) 
     { } 

     [DllImport("kernel32.dll")] 
     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
     [SuppressUnmanagedCodeSecurity] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     private static extern bool CloseHandle(IntPtr handle); 

     protected override bool ReleaseHandle() 
     { 
      return CloseHandle(handle); 
     } 
    } 
} 
+0

Pouvez-vous élaborer? Si MyThread était déjà en cours d'exécution, pouvons-nous changer son CurrentPrincipal? – Duncan

+0

oui, avez-vous suivi le lien? il y a des exemples là-bas. – dove

+0

Étonnamment ce lien m'a aidé à résoudre mon problème. Bien qu'il ne définisse pas l'identité Thread, il vous permet d'exécuter du code tout en usurpant l'identité d'un autre utilisateur. En examinant le premier exemple dans le lien, j'ai fait une copie de l'identité de l'utilisateur actuel dans mon thread principal en utilisant: var newId = WindowsIdentity.GetCurrent(); Ensuite, j'ai transmis cette identité à mes threads et j'ai usurpé l'identité de l'utilisateur avec cette clause: using (var impersonationContext = newId.Impersonate()) Le code exécuté dans l'utilisation s'exécutera sous l'identité Impersonated. – Sal

3

Ceci est une mise à jour de la réponse acceptée [ appliquer sur .NET framework 4.5 et supérieur]
En .NET 4.5 la propriété IsAuthenticated n'a pas d'accesseur défini, donc vous ne pouvez pas le définir directement comme la réponse acceptée.
Vous pouvez utiliser le code suivant pour définir cette propriété.

GenericIdentity identity = new GenericIdentity("someuser", "Forms"); 
Thread.CurrentPrincipal = new GenericPrincipal(identity, new string[] { "somerole" }); 
Questions connexes