C# 在另一个用户和域下打开共享文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1192631/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 10:29:19  来源:igfitidea点击:

Open a shared file under another user and domain?

c#ioimpersonation

提问by Ahmed Said

I have a C# console application that needs to read a shared file on a machine in another domain. When the application tries to access the file an exception occurs as the local user does not have permission to access the shared resource.

我有一个 C# 控制台应用程序需要读取另一个域中机器上的共享文件。当应用程序尝试访问该文件时,会发生异常,因为本地用户没有访问共享资源的权限。

Currently I overcome this problem manually by open the shared folder from the run and put the username and password into the windows authentication dialog then run the application.

目前,我通过从运行中打开共享文件夹并将用户名和密码放入 Windows 身份验证对话框中,然后运行应用程序来手动解决此问题。

How can I do it programmatically?

我怎样才能以编程方式做到这一点?

回答by Kane

From memory you'll need to use a Windows API call and login as a user on the other domain. See this linkfor an example.

根据记忆,您需要使用 Windows API 调用并以其他域上的用户身份登录。有关示例,请参阅此链接

Another idea could be to use the RunAs command line argument to read the file and save it into a file on your local domain/server.

另一个想法可能是使用 RunAs 命令行参数来读取文件并将其保存到本地域/服务器上的文件中。

回答by Anton Tykhyy

a) p/invoke LogonUserwith LOGON32_LOGON_NEW_CREDENTIALSand create a new WindowsIdentitywith the new token, then use normal file access.

a) p/invoke LogonUserwithLOGON32_LOGON_NEW_CREDENTIALSWindowsIdentity使用新令牌创建一个新令牌,然后使用正常的文件访问。

b) p/invoke WNetAddConnection3. Be advised that this makes your remote share accessible to every other process on your machine.

b) p/调用WNetAddConnection3。请注意,这将使您的计算机上的每个其他进程都可以访问您的远程共享。

c) WMI via System.Managementand CIM_DataFile; you won't even need p/invoke. System.Managementlets you specify credentials for remote machine.

c) WMI 通过System.ManagementCIM_DataFile;你甚至不需要 p/invoke。System.Management允许您为远程机器指定凭据。

回答by Ahmed Said

I used the point "a" as "Anton" suggested, I developed two versions for one class, first one using Win32 APIs and second uses WindowsIdentity class

我使用了“Anton”建议的点“a”,我为一个类开发了两个版本,第一个使用 Win32 API,第二个使用 WindowsIdentity 类

Version 1:

版本 1:

class UserImpersonation:IDisposable
    {       
        [DllImport("advapi32.dll")]
            public static extern int LogonUser(String lpszUserName,
                String lpszDomain,
                String lpszPassword,
                int dwLogonType,
                int dwLogonProvider,
                ref IntPtr phToken);

            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int DuplicateToken(IntPtr hToken,
                int impersonationLevel,
                ref IntPtr hNewToken);

            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool RevertToSelf();

            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            public static extern bool CloseHandle(IntPtr handle);

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

            WindowsImpersonationContext wic;
            string _userName;
            string _domain;
            string _passWord;
            public UserImpersonation(string userName, string domain, string passWord)
            {
                _userName = userName;
                _domain = domain;
                _passWord = passWord;
            }
            public bool ImpersonateValidUser()
            {
                WindowsIdentity wi;
                IntPtr token = IntPtr.Zero;
                IntPtr tokenDuplicate = IntPtr.Zero;

                if (RevertToSelf())
                {
                    if (LogonUser(_userName, _domain, _passWord, LOGON32_LOGON_INTERACTIVE,
                        LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            wi = new WindowsIdentity(tokenDuplicate);
                            wic = wi.Impersonate();
                            if (wic != null)
                            {
                                CloseHandle(token);
                                CloseHandle(tokenDuplicate);
                                return true;
                            }
                        }
                    }
                }
                if (token != IntPtr.Zero)
                    CloseHandle(token);
                if (tokenDuplicate != IntPtr.Zero)
                    CloseHandle(tokenDuplicate);
                return false;
            }

        #region IDisposable Members
            public void Dispose()
            {
                if(wic != null)
                 wic.Dispose();
                RevertToSelf();

            }
            #endregion
    }

Version2 (from MSDNwith small changes)

版本 2(来自MSDN,有小改动)

class UserImpersonation2:IDisposable
    {
        [DllImport("advapi32.dll")]
        public static extern bool LogonUser(String lpszUserName,
            String lpszDomain,
            String lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        WindowsImpersonationContext wic;
        IntPtr tokenHandle;
        string _userName;
        string _domain;
        string _passWord;

        public UserImpersonation2(string userName, string domain, string passWord)
        {
            _userName = userName;
            _domain = domain;
            _passWord = passWord;
        }

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

        public bool ImpersonateValidUser()
        {
            bool returnValue = LogonUser(_userName, _domain, _passWord,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                    ref tokenHandle);

            Console.WriteLine("LogonUser called.");

            if (false == returnValue)
            {
                int ret = Marshal.GetLastWin32Error();
                Console.WriteLine("LogonUser failed with error code : {0}", ret);
                return false;
            }

            Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
            Console.WriteLine("Value of Windows NT token: " + tokenHandle);

            // Check the identity.
            Console.WriteLine("Before impersonation: "
                + WindowsIdentity.GetCurrent().Name);
            // Use the token handle returned by LogonUser.
            WindowsIdentity newId = new WindowsIdentity(tokenHandle);
            wic = newId.Impersonate();

            // Check the identity.
            Console.WriteLine("After impersonation: "
                + WindowsIdentity.GetCurrent().Name);
            return true;
        }
        #region IDisposable Members
        public void Dispose()
        {
            if(wic!=null)
                wic.Undo();
            if (tokenHandle != IntPtr.Zero)
                CloseHandle(tokenHandle);

        }
        #endregion
    }

How to use (both are the same)

使用方法(两者都一样)

            const string file = @"\machine\test\file.txt";

            using (UserImpersonation user = new UserImpersonation("user", "domain", "password"))
            {
                if (user.ImpersonateValidUser())
                {
                    StreamReader reader = new StreamReader(file);
                    Console.WriteLine(reader.ReadToEnd());
                    reader.Close();
                }
            }