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

时间:2009-07-28 08:20:41

标签: c# io impersonation

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

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

如何以编程方式完成?

3 个答案:

答案 0 :(得分:3)

a)使用LOGON32_LOGON_NEW_CREDENTIALS调用LogonUser并使用新令牌创建新的WindowsIdentity,然后使用普通文件访问。

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

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

答案 1 :(得分:3)

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

版本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
    }

版本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
    }

如何使用(两者都相同)

            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();
                }
            }

答案 2 :(得分:0)

从内存中,您需要使用Windows API调用并以其他域上的用户身份登录。有关示例,请参阅此link

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