문제

.NET에서 사용자를 가장하는 상자에 간단한 방법이 있습니까?

지금까지 나는 사용하고 있습니다 코드 프로젝트 에서이 클래스 나의 모든 사칭 요구 사항에 대해.

.NET 프레임 워크를 사용하여 더 좋은 방법이 있습니까?

사용자 자격 증명 세트 (사용자 이름, 비밀번호, 도메인 이름)가 있으며, 이는 가장하는 데 필요한 신원을 나타냅니다.

도움이 되었습니까?

해결책

다음은 .NET 어세화 개념에 대한 좋은 개요입니다.

기본적으로 .NET Framework의 상자 밖에서이 클래스를 활용할 것입니다.

코드는 종종 길어질 수 있으므로 프로세스를 단순화하려는 참조와 같은 많은 예제를 보게됩니다.

다른 팁

.NET 공간의 "가장"은 일반적으로 특정 사용자 계정에서 코드를 실행하는 것을 의미합니다. 이 두 아이디어는 자주 함께 짝을 이루지 만 사용자 이름과 비밀번호를 통해 해당 사용자 계정에 액세스하는 것보다 다소 별도의 개념입니다. 나는 둘 다 설명하고 내 사용 방법을 설명하겠습니다. 간단한 혐오 내부적으로 사용하는 도서관.

인격화

사칭을위한 API는 .NET로 제공됩니다. System.Security.Principal 네임 스페이스 :

  • 최신 코드 (.NET 4.6+, .NET Core 등)는 일반적으로 사용해야합니다. WindowsIdentity.RunImpersonated, 이는 사용자 계정의 토큰에 대한 핸들을 수락 한 다음 Action 또는 Func<T> 코드가 실행됩니다.

    WindowsIdentity.RunImpersonated(tokenHandle, () =>
    {
        // do whatever you want as this user.
    });
    

    또는

    var result = WindowsIdentity.RunImpersonated(tokenHandle, () =>
    {
        // do whatever you want as this user.
        return result;
    });
    
  • 오래된 코드가 사용되었습니다 WindowsIdentity.Impersonate 검색 방법 a WindowsImpersonationContext 물체. 이 개체는 구현됩니다 IDisposable, 일반적으로 a에서 호출해야합니다 using 차단하다.

    using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(tokenHandle))
    {
        // do whatever you want as this user.
    }
    

    이 API는 여전히 .NET 프레임 워크에 존재하지만 일반적으로 피해야하며 .NET Core 또는 .NET 표준에서는 사용할 수 없습니다.

사용자 계정에 액세스합니다

Windows에서 사용자 계정에 액세스하기 위해 사용자 이름과 비밀번호를 사용하는 API는 다음과 같습니다. LogonUser - Win32 Native API입니다. 현재 .NET API를 부르기위한 내장 .NET API가 없으므로 P/Invoke에 의지해야합니다.

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

이것은 기본 통화 정의이지만 실제로 생산에서 사용하는 것이 더 많은 것이 있습니다.

  • "안전한"액세스 패턴으로 손잡이를 얻습니다.
  • 기본 핸들을 적절하게 닫습니다
  • CAS (Code Access Security) 신뢰 수준 (.NET 프레임 워크 만)
  • 통과 SecureString 사용자 키 스트로크를 통해 안전하게 수집 할 수 있습니다.

이 모든 것을 설명하기 위해 작성해야 할 코드의 양은 StackoverFlow 답변에 있어야하는 것 이상입니다.

결합되고 쉬운 접근

이 모든 것을 직접 쓰는 대신 내 사용을 고려하십시오. 간단한 혐오 도서관은 도서관과 사용자 액세스를 단일 API로 결합합니다. 동일한 간단한 API와 함께 현대 및 오래된 코드베이스에서 잘 작동합니다.

var credentials = new UserCredentials(domain, username, password);
Impersonation.RunAsUser(credentials, logonType, () =>
{
    // do whatever you want as this user.
}); 

또는

var credentials = new UserCredentials(domain, username, password);
var result = Impersonation.RunAsUser(credentials, logonType, () =>
{
    // do whatever you want as this user.
    return something;
});

그것과 매우 유사합니다 WindowsIdentity.RunImpersonated API이지만 토큰 핸들에 대해 아무것도 알 필요가 없습니다.

버전 3.0.0 기준 API입니다. 자세한 내용은 Project ReadMe를 참조하십시오. 또한 이전 버전의 라이브러리는 IDisposable 패턴과 비슷합니다 WindowsIdentity.Impersonate. 최신 버전은 훨씬 안전하며 둘 다 여전히 내부적으로 사용됩니다.

이것은 아마도 당신이 원하는 것일 것입니다.

using System.Security.Principal;
using(WindowsIdentity.GetCurrent().Impersonate())
{
     //your code goes here
}

그러나 나는 당신을 돕기 위해 더 많은 세부 사항이 필요합니다. 구성 파일 (웹 사이트 에서이 작업을 수행하려는 경우) 또는 WCF 서비스 인 경우 메소드 데코레이터 (속성)를 통해 가장 할 수 있습니다. 아이디어를 얻을 수 있습니다.

또한 특정 서비스 (또는 웹 앱)라는 클라이언트를 가장하는 것에 대해 이야기하는 경우 클라이언트를 올바르게 구성하여 적절한 토큰을 전달해야합니다.

마지막으로, 당신이 정말로 원하는 것이 대표단이라면, 사용자와 기계가 대표단을 신뢰할 수 있도록 광고를 올바르게 설정해야합니다.

편집하다:
구경하다 여기 다른 사용자를 가장하고 추가 문서를 찾는 방법을 확인하십시오.

Matt Johnson의 답변은 다음과 같습니다. 로그온 유형에 열거를 추가했습니다. LOGON32_LOGON_INTERACTIVE SQL Server에서 작동 한 최초의 열거 값이었습니다. 내 연결 문자열은 단지 신뢰했습니다. 연결 문자열에 사용자 이름 / 비밀번호가 없습니다.

  <PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
  Public Class Impersonation
    Implements IDisposable

    Public Enum LogonTypes
      ''' <summary>
      ''' This logon type is intended for users who will be interactively using the computer, such as a user being logged on  
      ''' by a terminal server, remote shell, or similar process.
      ''' This logon type has the additional expense of caching logon information for disconnected operations; 
      ''' therefore, it is inappropriate for some client/server applications,
      ''' such as a mail server.
      ''' </summary>
      LOGON32_LOGON_INTERACTIVE = 2

      ''' <summary>
      ''' This logon type is intended for high performance servers to authenticate plaintext passwords.
      ''' The LogonUser function does not cache credentials for this logon type.
      ''' </summary>
      LOGON32_LOGON_NETWORK = 3

      ''' <summary>
      ''' This logon type is intended for batch servers, where processes may be executing on behalf of a user without 
      ''' their direct intervention. This type is also for higher performance servers that process many plaintext
      ''' authentication attempts at a time, such as mail or Web servers. 
      ''' The LogonUser function does not cache credentials for this logon type.
      ''' </summary>
      LOGON32_LOGON_BATCH = 4

      ''' <summary>
      ''' Indicates a service-type logon. The account provided must have the service privilege enabled. 
      ''' </summary>
      LOGON32_LOGON_SERVICE = 5

      ''' <summary>
      ''' This logon type is for GINA DLLs that log on users who will be interactively using the computer. 
      ''' This logon type can generate a unique audit record that shows when the workstation was unlocked. 
      ''' </summary>
      LOGON32_LOGON_UNLOCK = 7

      ''' <summary>
      ''' This logon type preserves the name and password in the authentication package, which allows the server to make 
      ''' connections to other network servers while impersonating the client. A server can accept plaintext credentials 
      ''' from a client, call LogonUser, verify that the user can access the system across the network, and still 
      ''' communicate with other servers.
      ''' NOTE: Windows NT:  This value is not supported. 
      ''' </summary>
      LOGON32_LOGON_NETWORK_CLEARTEXT = 8

      ''' <summary>
      ''' This logon type allows the caller to clone its current token and specify new credentials for outbound connections.
      ''' The new logon session has the same local identifier but uses different credentials for other network connections. 
      ''' NOTE: This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
      ''' NOTE: Windows NT:  This value is not supported. 
      ''' </summary>
      LOGON32_LOGON_NEW_CREDENTIALS = 9
    End Enum

    <DllImport("advapi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function LogonUser(lpszUsername As [String], lpszDomain As [String], lpszPassword As [String], dwLogonType As Integer, dwLogonProvider As Integer, ByRef phToken As SafeTokenHandle) As Boolean
    End Function

    Public Sub New(Domain As String, UserName As String, Password As String, Optional LogonType As LogonTypes = LogonTypes.LOGON32_LOGON_INTERACTIVE)
      Dim ok = LogonUser(UserName, Domain, Password, LogonType, 0, _SafeTokenHandle)
      If Not ok Then
        Dim errorCode = Marshal.GetLastWin32Error()
        Throw New ApplicationException(String.Format("Could not impersonate the elevated user.  LogonUser returned error code {0}.", errorCode))
      End If

      WindowsImpersonationContext = WindowsIdentity.Impersonate(_SafeTokenHandle.DangerousGetHandle())
    End Sub

    Private ReadOnly _SafeTokenHandle As New SafeTokenHandle
    Private ReadOnly WindowsImpersonationContext As WindowsImpersonationContext

    Public Sub Dispose() Implements System.IDisposable.Dispose
      Me.WindowsImpersonationContext.Dispose()
      Me._SafeTokenHandle.Dispose()
    End Sub

    Public NotInheritable Class SafeTokenHandle
      Inherits SafeHandleZeroOrMinusOneIsInvalid

      <DllImport("kernel32.dll")> _
      <ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)> _
      <SuppressUnmanagedCodeSecurity()> _
      Private Shared Function CloseHandle(handle As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
      End Function

      Public Sub New()
        MyBase.New(True)
      End Sub

      Protected Overrides Function ReleaseHandle() As Boolean
        Return CloseHandle(handle)
      End Function
    End Class

  End Class

당신은 a와 함께 사용해야합니다 Using 가장 한 코드를 포함하는 진술.

이전 답변에서 자세한 내용보기 Nuget 패키지를 만들었습니다.너겟

코드 켜짐 github

샘플 : 사용할 수 있습니다.

           string login = "";
           string domain = "";
           string password = "";

           using (UserImpersonation user = new UserImpersonation(login, domain, password))
           {
               if (user.ImpersonateValidUser())
               {
                   File.WriteAllText("test.txt", "your text");
                   Console.WriteLine("File writed");
               }
               else
               {
                   Console.WriteLine("User not connected");
               }
           }

전체 코드 :

using System;
using System.Runtime.InteropServices;
using System.Security.Principal;


/// <summary>
/// Object to change the user authticated
/// </summary>
public class UserImpersonation : IDisposable
{
    /// <summary>
    /// Logon method (check athetification) from advapi32.dll
    /// </summary>
    /// <param name="lpszUserName"></param>
    /// <param name="lpszDomain"></param>
    /// <param name="lpszPassword"></param>
    /// <param name="dwLogonType"></param>
    /// <param name="dwLogonProvider"></param>
    /// <param name="phToken"></param>
    /// <returns></returns>
    [DllImport("advapi32.dll")]
    private static extern bool LogonUser(String lpszUserName,
        String lpszDomain,
        String lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);

    /// <summary>
    /// Close
    /// </summary>
    /// <param name="handle"></param>
    /// <returns></returns>
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern bool CloseHandle(IntPtr handle);

    private WindowsImpersonationContext _windowsImpersonationContext;
    private IntPtr _tokenHandle;
    private string _userName;
    private string _domain;
    private string _passWord;

    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;

    /// <summary>
    /// Initialize a UserImpersonation
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="domain"></param>
    /// <param name="passWord"></param>
    public UserImpersonation(string userName, string domain, string passWord)
    {
        _userName = userName;
        _domain = domain;
        _passWord = passWord;
    }

    /// <summary>
    /// Valiate the user inforamtion
    /// </summary>
    /// <returns></returns>
    public bool ImpersonateValidUser()
    {
        bool returnValue = LogonUser(_userName, _domain, _passWord,
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                ref _tokenHandle);

        if (false == returnValue)
        {
            return false;
        }

        WindowsIdentity newId = new WindowsIdentity(_tokenHandle);
        _windowsImpersonationContext = newId.Impersonate();
        return true;
    }

    #region IDisposable Members

    /// <summary>
    /// Dispose the UserImpersonation connection
    /// </summary>
    public void Dispose()
    {
        if (_windowsImpersonationContext != null)
            _windowsImpersonationContext.Undo();
        if (_tokenHandle != IntPtr.Zero)
            CloseHandle(_tokenHandle);
    }

    #endregion
}

나는 파티에 꽤 늦었다는 것을 알고 있지만 도서관은 필립 앨런 하드 링, 그것은이 사건과 비슷한 경우에 가장 적합한 것입니다.

이와 같은 작은 코드 만 있으면됩니다.

private const string LOGIN = "mamy";
private const string DOMAIN = "mongo";
private const string PASSWORD = "HelloMongo2017";

private void DBConnection()
{
    using (Impersonator user = new Impersonator(LOGIN, DOMAIN, PASSWORD, LogonType.LOGON32_LOGON_NEW_CREDENTIALS, LogonProvider.LOGON32_PROVIDER_WINNT50))
    {
    }
}

그리고 그의 수업을 추가하십시오 :

.NET (C#) 네트워크 자격 증명을 가진 가장

네트워크 자격 증명을 갖기 위해 가장 된 로그온이 필요한 경우 예제를 사용할 수 있지만 더 많은 옵션이 있습니다.

이 솔루션을 사용할 수 있습니다. (Nuget 패키지 사용) 소스 코드는 다음과 같습니다. Github :https://github.com/michelcedric/userimpersonation

자세한 세부 사항https://michelcedric.wordpress.com/2015/09/03/usurpation-didentite-dun-user-c-user-mipersonation/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top