通常系統中如果要區分windows權限只要在IIS內設定好即可,但有時候可能為了控管windows帳號的權限,不可能把所有的權限都開給系統帳號,比方說檔案上傳至某些目錄,系統帳號並無權限寫入,這個時候就需要切換帳號。

以下是撰寫一個切換身分的helper,相信網路上很多人都寫過了,主要概念就是

  • 要使用advapi32.dll,他不是屬於.net類別庫的,我們主要使用 LogonUser 方法
  • LogonUser須傳入username(帳號),domain(網域),password(密碼),LOGON32_LOGON_INTERACTIVE(登入類別),LOGON32_PROVIDER_DEFAULT(提供者)
  • LogonUser會取得Token(out UserToken)
  • 登入完之後須登出帳號,這裡要使用kernel32.dll,同樣也不是屬於.net類別庫,我們主要使用 CloseHandle 方法,須傳入LogonUser取得的Token
  • 撰寫Impersonation Helper

    using System.Security.Principal;
    namespace Recruit.Impersonator
        public class Impersonator : System.IDisposable
            //登入提供者
            protected const int LOGON32_PROVIDER_DEFAULT = 0;
            protected const int LOGON32_LOGON_INTERACTIVE = 2;
            public WindowsIdentity Identity = null;
            private System.IntPtr m_accessToken;
            [System.Runtime.InteropServices.DllImport("advapi32.dll", SetLastError = true)]
            private static extern bool LogonUser(string lpszUsername, string lpszDomain,
            string lpszPassword, int dwLogonType, int dwLogonProvider, ref System.IntPtr phToken);
            [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
            private extern static bool CloseHandle(System.IntPtr handle);
            public Impersonator()
                //建構子
            public void Login(string username, string domain, string password)
                if (this.Identity != null)
                    this.Identity.Dispose();
                    this.Identity = null;
                    this.m_accessToken = new System.IntPtr(0);
                    Logout();
                    this.m_accessToken = System.IntPtr.Zero;
                    //執行LogonUser
                    bool isSuccess = LogonUser(
                       username,
                       domain,
                       password,
                       LOGON32_LOGON_INTERACTIVE,
                       LOGON32_PROVIDER_DEFAULT,
                       ref this.m_accessToken);
                    if (!isSuccess)
                        //取得錯誤碼
                        int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
                        throw new System.ComponentModel.Win32Exception(error);
                    Identity = new WindowsIdentity(this.m_accessToken);
                catch
                    throw;
            //使用完之後登出,放在Dispose中呼叫
            public void Logout()
                if (this.m_accessToken != System.IntPtr.Zero)
                    CloseHandle(m_accessToken);
                this.m_accessToken = System.IntPtr.Zero;
                if (this.Identity != null)
                    this.Identity.Dispose();
                    this.Identity = null;
            void System.IDisposable.Dispose()
                Logout();
    

    .net core切換身分
    這邊要使用WindowsIdentity.RunImpersonated,傳入剛剛的token,並且第二個參數是Action,切換身分之後要做的事情

     using (Impersonator.Impersonator impersonator = new Impersonator.Impersonator()){
     System.Security.Principal.WindowsIdentity.RunImpersonated(impersonator.Identity.AccessToken, () =>
         //做切換後身分的事情
    https://dotblogs.com.tw/supershowwei/2016/01/26/175448
    https://blog.darkthread.net/blog/impersonate/
    https://docs.microsoft.com/zh-tw/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio
    https://docs.microsoft.com/zh-tw/troubleshoot/aspnet/implement-impersonation
    https://docs.microsoft.com/zh-tw/dotnet/api/system.security.principal.windowsidentity.runimpersonated?view=dotnet-plat-ext-3.1