时间:2021-05-20
透过程式存取Windows网路分享的档案也算常见需求,但存取身分是个问题。之前我惯用的技巧是用有权限的AD网域帐号执行排程存取网路分享,但这招要搬进网站或遇到不同网路分享用不同帐号便会破功。最近遇上类似议题,直觉要得回头靠WinAPI Impersonation解决,之前曾写过通用元件,担心11年前Windows Vista/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 (var ctxA = NetworkCopier.GetConnetionContext("\\SvrA\Share", MyAD", "userX", "***"){ using (var ctxB = 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\,为省去人工截取的麻烦,我写了一段正则表达式更顺手。
完整程式如下,需要的朋友请自取使用:
using System;using System.Collections.Generic;using System.ComponentModel;using System.IO;using System.Linq;using System.Net;using System.Runtime.InteropServices;using System.Text.RegularExpressions;using System.Web;namespace MyApp.Models{ public class NetworkCopier { static string defaultDomain = null; static string defaultUserId = null; static string defaultPasswd = null; static NetworkCopier() { try { //TODO: 由設定檔、Registry 或 DB 取得帳號設定,密碼記得要加密保存 var p = ReadCredentialInfo().Split('\t'); defaultDomain = p[0]; defaultUserId = p[1]; defaultPasswd = p[2]; } catch { } } static string NotNull(string s) { if (string.IsNullOrEmpty(s)) throw new ApplicationException("未設定預設登入身分"); return s; } static string DefaultDomain => NotNull(defaultDomain); static string DefaultUserId => NotNull(defaultUserId); static string DefaultPassword => NotNull(defaultPasswd); static string GetSharePath(string path) { var m = Regex.Match(path, @"^\\\\[^\\]+\\[^\\]+"); if (m.Success) return m.Value; return path; } public static void Copy(string srcPath, string dstPath, string domain = null, string userId = null, string passwd = null) { using (new NetworkConnection(GetSharePath(srcPath), new NetworkCredential(userId ?? DefaultUserId, passwd ?? DefaultPassword, domain ?? DefaultDomain))) { File.Copy(srcPath, dstPath); } } public static string[] DirFiles(string path, string pattern, string domain = null, string userId = null, string passwd = null) { using (new NetworkConnection(GetSharePath(path), new NetworkCredential(userId ?? DefaultUserId, passwd ?? DefaultPassword, domain ?? DefaultDomain))) { return Directory.GetFiles(path, pattern); } } public static GetConnectionContext(string path, string domain = null, string userId = null, string passwd = null) { return new NetworkConnection(GetSharePath(path), new NetworkCredential(userId ?? DefaultUserId, passwd ?? DefaultPassword, domain ?? DefaultDomain)); } } //引用來源: https://stackoverflow.com/a/1197430/288936 public class NetworkConnection : IDisposable { string _networkName; public NetworkConnection(string networkName, NetworkCredential credentials) { _networkName = networkName; var netResource = new NetResource() { Scope = ResourceScope.GlobalNetwork, ResourceType = ResourceType.Disk, DisplayType = ResourceDisplaytype.Share, RemoteName = networkName }; var userName = string.IsNullOrEmpty(credentials.Domain) ? credentials.UserName : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName); var result = WNetAddConnection2( netResource, credentials.Password, userName, 0); if (result != 0) { throw new Win32Exception(result); } } ~NetworkConnection() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { WNetCancelConnection2(_networkName, 0, true); } [DllImport("mpr.dll")] private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags); [DllImport("mpr.dll")] private static extern int WNetCancelConnection2(string name, int flags, bool force); } [StructLayout(LayoutKind.Sequential)] public class NetResource { public ResourceScope Scope; public ResourceType ResourceType; public ResourceDisplaytype DisplayType; public int Usage; public string LocalName; public string RemoteName; public string Comment; public string Provider; } public enum ResourceScope : int { Connected = 1, GlobalNetwork, Remembered, Recent, Context }; public enum ResourceType : int { Any = 0, Disk = 1, Print = 2, Reserved = 8, } public enum ResourceDisplaytype : 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网路共享的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
路由器登录密码忘记了怎么办?首先尝试初始默认密码,由于大多数的初始默认帐号密码都是admin,因此如果在帐号密码没有改动的情况下,先尝试初始帐号密码,试试是
192.168.1.1(不管是插网线还是用无线,只要电脑连上了无线路由猫就能进入)。 3、这时会让输入帐号密码,一般帐号密码都是admin,在路由底部会有写的
192.168.1.1192.168.0.1 2.还是输入密码,一般帐号密码都是admin。或者帐号是admin密码是空,如果还是不行,看说明书吧。 3.应
192.168.1.1,输入浏览器的地址栏回车,然后输入自己的管理帐号密码登录即可,(帐号密码如果没修改过,一般都在路由器的包装盒子上)。 二、在路由器管理界
忘记华为帐号密码可以通过手机端的设置-华为帐号,或者通过电脑端-华为商城重置新密码。华为帐号找回密码教程一、手机步骤1、在华为帐号登录界面-右上角三点图标-安全