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的格式一定要正確,,否則可能出現(xiàn)錯(cuò)誤
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:開(kāi)頭的URI,,所以可以用WebClient類來(lái)傳輸文件,。
添加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)
{
// 如果網(wǎng)絡(luò)很慢,而文件又很大,,這時(shí)可能有超時(shí)異常(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)
{
// 如果網(wǎng)絡(luò)很慢,而文件又很大,,這時(shí)可能有超時(shí)異常(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來(lái)訪問(wèn)遠(yuǎn)程資源,。
// 如果要(通過(guò)模擬用戶獲得權(quán)限)實(shí)現(xiàn)服務(wù)器程序,訪問(wèn)本地授權(quán)數(shù)據(jù)庫(kù)可
// 以用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();
}
}
}
}
五,、比較
方法一通過(guò)調(diào)用Shell命令Net Use實(shí)現(xiàn),,有點(diǎn)笨拙。
方法二和方法一有些相似之處,。映射遠(yuǎn)程資源,,然后訪問(wèn)。
方法三由于會(huì)有超時(shí)異常出現(xiàn),,所以在網(wǎng)絡(luò)速度快,、傳輸小文件時(shí)是可以的,。
方法四通過(guò)身份模擬實(shí)現(xiàn)遠(yuǎn)程資源訪問(wèn)。一些服務(wù)器進(jìn)程就是通過(guò)這種方式運(yùn)行的,。這種方法也是我的最愛(ài),。
六、要注意的地方
關(guān)于這幾種方法,,google后都可以找到一些文章,。但是等到自己實(shí)際測(cè)試時(shí),有時(shí)會(huì)出現(xiàn)各種小錯(cuò)誤,,
這些錯(cuò)誤基本來(lái)源于兩方面:
1,、函數(shù)的參數(shù)選擇有問(wèn)題,和自己的環(huán)境不相符,。
比如
public static extern int LogonUser(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
中的dwLogonType,,要訪問(wèn)遠(yuǎn)程資源就要用LOGON32_LOGON_NEW_CREDENTIALS,
要模擬本機(jī)用戶就要用LOGON32_LOGON_INTERACTIVE,。
2,、函數(shù)的參數(shù)格式有問(wèn)題。
a,、比如
public static extern int LogonUser(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
中的lpszUserName,、lpszDomain、lpszPassword就要寫清楚,。
我就在這遇到過(guò)問(wèn)題,,第一次測(cè)試時(shí),遠(yuǎn)程服務(wù)器就是一臺(tái)獨(dú)立的文件服務(wù)器,,這是我的調(diào)用方式:
LogonUser("myname", "192.168.1.48", "password", LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_DEFAULT, ref token);
第二次測(cè)試時(shí),,遠(yuǎn)程服務(wù)器是域MyDomain中的一個(gè)成員服務(wù)器,提供文件服務(wù),。這時(shí)代碼就應(yīng)該是:
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\”就會(huì)出錯(cuò),;
如果是域中的用戶,那么把@"Domain\UserName"變成@"UserName"就會(huì)出錯(cuò),。