c# 使用特定帐号密码访问Windows网路共享
透过程式存取Windows网路分享的档案也算常见需求,但存取身分是个问题。之前我惯用的技巧是用有权限的AD网域帐号执行排程存取网路分享,但这招要搬进网站或遇到不同网路分享用不同帐号便会破功。最近遇上类似议题,直觉要得回头靠WinAPIImpersonation解决,之前曾写过通用元件,担心11年前WindowsVista/7时代的作品有点过时,就爬文找找更好的做法。
之前的变身做法是改变Thread的执行身分,然而针对网路分享还有另一个WinAPI-WNetAddConnection2,可做到对多个网路分享使用不同登入身分。在stackoverflow找到有人分享把它包成搭配using使用的Context物件,符合我惯用的风格,二话不说,按赞并写文分享。
为方便使用,我再做了一层包装,写了一个NetworkCopier,将查目录或复制档案动作简化成Copy(srcNetPath,targetPath,domain,userId,passwd)、DirFiles(srcNetPath,domain,userId,passwd),并支援预设帐密可省略输入domain,userId,passwd;另外还有GetConnetionContext(path,domain,userId,passwd)可取回NetworkConnection物件方便用同一连线身分进行多项操作,若来源与目的属不同网路分享则可套叠多重身分,写成:
using(varctxA=NetworkCopier.GetConnetionContext("\\SvrA\Share",MyAD","userX","***")
{
using(varctxB=NetworkCopier.GetConnetionContext("\\SvrB\Share",MyAD","userY","***")
{
File.Copy(@"\\SvrA\Share\SubFolder\test.txt",@"\\SvrB\Share\test.txt");
File.Copy(@"\\SvrA\Share\hello.txt",@"\\SvrB\Share\Temp\hello.txt");
}
}
建立NetworkConnection时,需要引入共享路径而不是完整路径,例如要访问\\SvrA\Share\SubFolder\test.txt,建立NetworkConnection的参数为\\SvrA\Share\,为省去人工截取的麻烦,我写了一段正则表达式更顺手。
完整程式如下,需要的朋友请自取使用:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.IO;
usingSystem.Linq;
usingSystem.Net;
usingSystem.Runtime.InteropServices;
usingSystem.Text.RegularExpressions;
usingSystem.Web;
namespaceMyApp.Models
{
publicclassNetworkCopier
{
staticstringdefaultDomain=null;
staticstringdefaultUserId=null;
staticstringdefaultPasswd=null;
staticNetworkCopier()
{
try
{
//TODO:由設定檔、Registry或DB取得帳號設定,密碼記得要加密保存
varp=ReadCredentialInfo().Split('\t');
defaultDomain=p[0];
defaultUserId=p[1];
defaultPasswd=p[2];
}
catch{}
}
staticstringNotNull(strings)
{
if(string.IsNullOrEmpty(s))
thrownewApplicationException("未設定預設登入身分");
returns;
}
staticstringDefaultDomain=>NotNull(defaultDomain);
staticstringDefaultUserId=>NotNull(defaultUserId);
staticstringDefaultPassword=>NotNull(defaultPasswd);
staticstringGetSharePath(stringpath)
{
varm=Regex.Match(path,@"^\\\\[^\\]+\\[^\\]+");
if(m.Success)returnm.Value;
returnpath;
}
publicstaticvoidCopy(stringsrcPath,stringdstPath,stringdomain=null,stringuserId=null,stringpasswd=null)
{
using(newNetworkConnection(GetSharePath(srcPath),
newNetworkCredential(userId??DefaultUserId,passwd??DefaultPassword,domain??DefaultDomain)))
{
File.Copy(srcPath,dstPath);
}
}
publicstaticstring[]DirFiles(stringpath,stringpattern,stringdomain=null,stringuserId=null,stringpasswd=null)
{
using(newNetworkConnection(GetSharePath(path),
newNetworkCredential(userId??DefaultUserId,passwd??DefaultPassword,domain??DefaultDomain)))
{
returnDirectory.GetFiles(path,pattern);
}
}
publicstaticGetConnectionContext(stringpath,stringdomain=null,stringuserId=null,stringpasswd=null)
{
returnnewNetworkConnection(GetSharePath(path),
newNetworkCredential(userId??DefaultUserId,passwd??DefaultPassword,domain??DefaultDomain));
}
}
//引用來源:https://stackoverflow.com/a/1197430/288936
publicclassNetworkConnection:IDisposable
{
string_networkName;
publicNetworkConnection(stringnetworkName,NetworkCredentialcredentials)
{
_networkName=networkName;
varnetResource=newNetResource()
{
Scope=ResourceScope.GlobalNetwork,
ResourceType=ResourceType.Disk,
DisplayType=ResourceDisplaytype.Share,
RemoteName=networkName
};
varuserName=string.IsNullOrEmpty(credentials.Domain)
?credentials.UserName
:string.Format(@"{0}\{1}",credentials.Domain,credentials.UserName);
varresult=WNetAddConnection2(
netResource,
credentials.Password,
userName,
0);
if(result!=0)
{
thrownewWin32Exception(result);
}
}
~NetworkConnection()
{
Dispose(false);
}
publicvoidDispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protectedvirtualvoidDispose(booldisposing)
{
WNetCancelConnection2(_networkName,0,true);
}
[DllImport("mpr.dll")]
privatestaticexternintWNetAddConnection2(NetResourcenetResource,stringpassword,stringusername,intflags);
[DllImport("mpr.dll")]
privatestaticexternintWNetCancelConnection2(stringname,intflags,boolforce);
}
[StructLayout(LayoutKind.Sequential)]
publicclassNetResource
{
publicResourceScopeScope;
publicResourceTypeResourceType;
publicResourceDisplaytypeDisplayType;
publicintUsage;
publicstringLocalName;
publicstringRemoteName;
publicstringComment;
publicstringProvider;
}
publicenumResourceScope:int
{
Connected=1,
GlobalNetwork,
Remembered,
Recent,
Context
};
publicenumResourceType:int
{
Any=0,
Disk=1,
Print=2,
Reserved=8,
}
publicenumResourceDisplaytype:int
{
Generic=0x0,
Domain=0x01,
Server=0x02,
Share=0x03,
File=0x04,
Group=0x05,
Network=0x06,
Root=0x07,
Shareadmin=0x08,
Directory=0x09,
Tree=0x0a,
Ndscontainer=0x0b
}
}
以上就是c#使用特定帐号密码访问Windows网路共享的详细内容,更多关于c#访问Windows网路共享的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。