c# 使用特定帐号密码访问Windows网路共享

透过程式存取Windows网路分享的档案也算常见需求,但存取身分是个问题。之前我惯用的技巧是用有权限的AD网域帐号执行排程存取网路分享,但这招要搬进网站或遇到不同网路分享用不同帐号便会破功。最近遇上类似议题,直觉要得回头靠WinAPI Impersonation解决,之前曾写过通用元件,担心11年前Windows Vista/7时代的作品有点过时,就爬文找找更好的做法。

之前的变身做法是改变Thread的执行身分,然而针对网路分享还有另一个WinAPI - WNetAddConnection2,可做到对多个网路分享使用不同登入身分。在stackoverflow找到有人分享把它https://www.jb51.net/article/206807.htm包成搭配using使用的Context物件,符合我惯用的风格,二话不说,按赞并写文分享。

为方便使用,我再做了一层包装,写了一个NetworkCopier,将查目录或复制档案动作简化成Copy(srcNetPath, targetPath, domain, userId, passwd)、DirFiles(srcNetPath, domain, userId, passwd),并支援预设帐密可省略输入domain, userId, passwd;另外还有GetConnetionContext(path, domain, userId, passwd) 可取回NetworkConnection 物件方便用同一连线身分进行多项操作,若来源与目的属不同网路分享则可套叠多重身分,写成:

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
}
}
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网路共享的详细内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值