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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。