[2020铁人赛] Day29 - 切换身分Impersonation

通常系统中如果要区分windows权限只要在IIS内设定好即可,但有时候可能为了控管windows帐号的权限,不可能把所有的权限都开给系统帐号,比方说档案上传至某些目录,系统帐号并无权限写入,这个时候就需要切换帐号。

前置作业
以下是撰写一个切换身分的helper,相信网路上很多人都写过了,主要概念就是

  1. 要使用advapi32.dll,他不是属於.net类别库的,我们主要使用LogonUser方法
  2. LogonUser须传入username(帐号),domain(网域),password(密码),LOGON32_LOGON_INTERACTIVE(登入类别),LOGON32_PROVIDER_DEFAULT(提供者)
  3. LogonUser会取得Token(out UserToken)
  4. 登入完之後须登出帐号,这里要使用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;
            }
            try
            {
                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


<<:  [Day 29]用Django架构建置专属的LINEBOT吧 - LIFF(II)Django Template样板

>>:  [Kata] Clojure - Day 30

视觉化当日趋势图(1)-client端架设&&工具篇

昨天我们完成了用Flask撰写ticks API, API端好了之後,接下来我们要开始架设我们的cl...

[Vue2] 从初学到放弃 Day7-怎麽变化里面的值

先用官网里面的范例 <div id="example"> <p...

闭包 跟 scope chain

人脑编译器 来一遍1 var a=1; function outerFun(){ let b=2; ...

Day9 Goroutine

并发 vs并行 并发运算就是多线程运算,且并发(concurrency)并非并行(Paralleli...

Day35 | WebView元件开发 - Webpack打包工具整合地雷陷阱排除

大家好,今天继续来开发元件,并动手解决实务上我们遇到的设定配置的问题。在昨天的练习里,我们可以使用b...