C#訪問遠端主機資源的方法

sudme發表於2011-08-09
最近要實現訪問遠端主機的共享目錄中的一個檔案。遇到了許可權問題。google了一下,找到了幾種解決方法,記錄如下:一、呼叫Net use命令 // 使用方法:[@more@]
//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.48sharefolder"
// 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.48generals";
string local = @"P:";
string username = @"DomainUserName";
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();
NetworkCredential 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.48generalsnow.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.48generals";
string local = @"P:";
string username = @"DomainUserName";
string password = @"Password";
如果@"192.168.1.48generals"變成@"192.168.1.48generals”就會出錯;
如果是域中的使用者,那麼把@"DomainUserName"
變成@"UserName"就會出錯。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26152447/viewspace-1053651/,如需轉載,請註明出處,否則將追究法律責任。

相關文章