您的位置:首页 > 编程语言 > C#

C#访问远程主机资源的方法

2016-08-29 03:56 429 查看
最近要实现访问远程主机的共享目录中的一个文件。遇到了权限问题。google了一下,找到了几种解决方法,记录如下:

一、调用Net use命令

        // 使用方法:

        //if (Connect("192.168.1.48", "用户名", "密码"))  

        //{

        //    File.Copy(@"\\192.168.1.48\共享目录\test.txt",   @"e:\\test.txt",   true);  

        //}

        public bool Connect(string remoteHost, string userName, string passWord)

        {

            bool Flag = true;

            Process proc = new Process();

            proc.StartInfo.FileName = "cmd.exe";

            proc.StartInfo.UseShellExecute = false;

            proc.StartInfo.RedirectStandardInput = true;

            proc.StartInfo.RedirectStandardOutput = true;

            proc.StartInfo.RedirectStandardError = true;

            proc.StartInfo.CreateNoWindow = true;

            try

            {

                proc.Start();

                string command = @"net  use  \\" + remoteHost + "  " + passWord + "  " + "  /user:" + userName + ">NUL";
                proc.StandardInput.WriteLine(command);

                command = "exit";

                proc.StandardInput.WriteLine(command);

                while (proc.HasExited == false)

                {

                    proc.WaitForExit(1000);

                }

                string errormsg = proc.StandardError.ReadToEnd();

                if (errormsg != "")

                    Flag = false;

                proc.StandardError.Close();

            }

            catch (Exception ex)

            {

                Flag = false;

            }

            finally

            {

                proc.Close();

                proc.Dispose();

            }

            return Flag;

        }

二、调用WNetAddConnection2、WNetAddConnection3或者NetUseAdd函数,进行磁盘映射。

using System;

using System.Collections.Generic;

using System.Text;      

using System.Runtime.InteropServices;

namespace WindowsApplication1

{

    public class MyMap

    {

        [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")]

        public static extern uint WNetAddConnection2(

            [In] NETRESOURCE lpNetResource,

            string lpPassword,

            string lpUsername,

            uint dwFlags);

       

        [DllImport("Mpr.dll")]

        public static extern uint WNetCancelConnection2(

            string lpName,

            uint dwFlags,

            bool fForce);

       

        [StructLayout(LayoutKind.Sequential)]

        public class NETRESOURCE

        {

            public int dwScope;

            public int dwType;

            public int dwDisplayType;

            public int dwUsage;

            public string LocalName;

            public string RemoteName;

            public string Comment;

            public string Provider;

        }

        // remoteNetworkPath format:  @"\\192.168.1.48\sharefolder"

        // localDriveName format:     @"E:"
        public static bool CreateMap(string userName, string password, string remoteNetworkPath, string localDriveName)

        {           

            NETRESOURCE myNetResource = new NETRESOURCE();

            myNetResource.dwScope = 2;       //2:RESOURCE_GLOBALNET

            myNetResource.dwType = 1;        //1:RESOURCETYPE_ANY

            myNetResource.dwDisplayType = 3; //3:RESOURCEDISPLAYTYPE_GENERIC

            myNetResource.dwUsage = 1;       //1: RESOURCEUSAGE_CONNECTABLE

            myNetResource.LocalName = localDriveName;

            myNetResource.RemoteName = remoteNetworkPath;

            myNetResource.Provider = null;

            uint nret = WNetAddConnection2(myNetResource, password, userName, 0);

            if (nret == 0)

                return true;

            else

                return false;

        }

        // localDriveName format:     @"E:"

        public static bool DeleteMap(string localDriveName)

        {

            uint nret = WNetCancelConnection2(localDriveName, 1, true);

            if (nret == 0)

                return true;

            else

                return false;

        }

        public void test()

        {

            // 注意:

            // remote、local、username的格式一定要正确,否则可能出现错误
            string remote = @"\\192.168.1.48\generals";

            string local = @"P:";
            string username = @"Domain\UserName";
            string password = @"Password";
            bool ret = MyMap.CreateMap(username, password, remote, local);

            if (ret)

            {

                //do what you want:

                // ...

                //File.Copy("q:\\test.htm", "c:\\test.htm");

                MyMap.DeleteMap(local);

            }

        }

    }

}

三、使用WebClient类

由于WebClient类可以上传下载文件,并且支持以http:、https:和file:开头的URI,所以可以用WebClient类来传输文件。

添加System.Net命名空间后使用如下代码下载文件:

        private void Test1()

        {

            try

            {

                WebClient client = new WebClient();

                Network
4000
Credential cred = new NetworkCredential("username", "password", "172.16.0.222");

                client.Credentials = cred;

                client.DownloadFile("file://172.16.0.222/test/111.txt", "111.txt");

            }

            catch (Exception ex)

            {

                // 如果网络很慢,而文件又很大,这时可能有超时异常(Time out)。

            }

        }

        public void Test2()

        {

            try

            {

                WebClient client = new WebClient();

                NetworkCredential cred = new NetworkCredential("username", "password", "domain");

                client.Credentials = cred;

                client.DownloadFile("file://172.16.0.222/test/111.txt", "111.txt");

            }

            catch (Exception ex)

            {

                // 如果网络很慢,而文件又很大,这时可能有超时异常(Time out)。

            }

        }

类似的还可以试试WebRequest、FileWebRequest等:

                WebRequest req = WebRequest.Create("file://138.12.12.14/generals/test.htm");

                NetworkCredential cred = new NetworkCredential("username", "password", "IP");

                req.Credentials = cred;

                WebResponse response = req.GetResponse();

                Stream strm = response.GetResponseStream();

                StreamReader r = new StreamReader(strm);

                ... ...

四、角色模拟

using System;

using System.Collections.Generic;

using System.Text;

using System.Runtime.InteropServices;

using System.Security.Principal;

using System.IO;

namespace Test

{

    public class Test

    {

        // logon types

        const int LOGON32_LOGON_INTERACTIVE = 2;

        const int LOGON32_LOGON_NETWORK = 3;

        const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

        // logon providers

        const int LOGON32_PROVIDER_DEFAULT = 0;

        const int LOGON32_PROVIDER_WINNT50 = 3;

        const int LOGON32_PROVIDER_WINNT40 = 2;

        const int LOGON32_PROVIDER_WINNT35 = 1;

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]

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

        private WindowsImpersonationContext impersonationContext;

        public bool impersonateValidUser(String userName, String domain, String password)

        {

            WindowsIdentity tempWindowsIdentity;

            IntPtr token = IntPtr.Zero;

            IntPtr tokenDuplicate = IntPtr.Zero;

            if (RevertToSelf())

            {

                // 这里使用LOGON32_LOGON_NEW_CREDENTIALS来访问远程资源。

                // 如果要(通过模拟用户获得权限)实现服务器程序,访问本地授权数据库可

                // 以用LOGON32_LOGON_INTERACTIVE

                if (LogonUser(userName, domain, password,
LOGON32_LOGON_NEW_CREDENTIALS,

                    LOGON32_PROVIDER_DEFAULT, ref token) != 0)

                {

                    if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)

                    {

                        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);

                        impersonationContext = tempWindowsIdentity.Impersonate();

                        if (impersonationContext != null)

                        {

                            System.AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

                            IPrincipal pr = System.Threading.Thread.CurrentPrincipal;

                            IIdentity id = pr.Identity;

                            CloseHandle(token);

                            CloseHandle(tokenDuplicate);

                            return true;

                        }

                    }

                }

            }

            if (token != IntPtr.Zero)

                CloseHandle(token);

            if (tokenDuplicate != IntPtr.Zero)

                CloseHandle(tokenDuplicate);

            return false;

        }

        public void undoImpersonation()

        {

            impersonationContext.Undo();

        }

        public void TestFunc()

        {

            bool isImpersonated = false;

            try

            {

                if (impersonateValidUser("UserName", "Domain", "Password"))

                {

                    isImpersonated = true;

                    //do what you want now, as the special user

                    // ...

                    File.Copy(@"\\192.168.1.48\generals\now.htm", "c:\\now.htm", true);

                }

            }

            finally

            {

                if (isImpersonated)

                    undoImpersonation();

            }

        }

    }

}

五、比较

方法一通过调用Shell命令Net Use实现,有点笨拙。

方法二和方法一有些相似之处。映射远程资源,然后访问。

方法三由于会有超时异常出现,所以在网络速度快、传输小文件时是可以的。

方法四通过身份模拟实现远程资源访问。一些服务器进程就是通过这种方式运行的。这种方法也是我的最爱。

六、要注意的地方

关于这几种方法,google后都可以找到一些文章。但是等到自己实际测试时,有时会出现各种小错误,

这些错误基本来源于两方面:

1、函数的参数选择有问题,和自己的环境不相符。
比如       

public static extern int LogonUser(String lpszUserName,

            String lpszDomain,

            String lpszPassword,

            int dwLogonType,

            int dwLogonProvider,

            ref IntPtr phToken);

中的dwLogonType,要访问远程资源就要用LOGON32_LOGON_NEW_CREDENTIALS,

要模拟本机用户就要用LOGON32_LOGON_INTERACTIVE。

2、函数的参数格式有问题。

    a、比如

    public static extern int LogonUser(String lpszUserName,

            String lpszDomain,

            String lpszPassword,

            int dwLogonType,

            int dwLogonProvider,

            ref IntPtr phToken);

    中的lpszUserName、lpszDomain、lpszPassword就要写清楚。

    我就在这遇到过问题,第一次测试时,远程服务器就是一台独立的文件服务器,这是我的调用方式:

        LogonUser("myname", "192.168.1.48", "password", LOGON32_LOGON_NEW_CREDENTIALS,

                    LOGON32_PROVIDER_DEFAULT, ref token);

    第二次测试时,远程服务器是域MyDomain中的一个成员服务器,提供文件服务。这时代码就应该是:

        LogonUser("myname", "MyDomain", "password", LOGON32_LOGON_NEW_CREDENTIALS,

                    LOGON32_PROVIDER_DEFAULT, ref token);

    注意,代码中是MyDomain而不是IP地址。

    b、再如:

    参考上面代码

            string remote = @"\\192.168.1.48\generals";

            string local = @"P:";
            string username = @"Domain\UserName";
            string password = @"Password";

    如果@"\\192.168.1.48\generals"变成@"\\192.168.1.48\generals\”就会出错;

    如果是域中的用户,那么把@"Domain\UserName"变成@"UserName"就会出错。

//原文链接http://www.cnblogs.com/h2appy/archive/2008/05/21/1204277.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: