c# 使用特定帳號密碼訪問Windows網(wǎng)路共享
透過程式存取Windows網(wǎng)路分享的檔案也算常見需求,但存取身分是個問題。之前我慣用的技巧是用有權(quán)限的AD網(wǎng)域帳號執(zhí)行排程存取網(wǎng)路分享,但這招要搬進網(wǎng)站或遇到不同網(wǎng)路分享用不同帳號便會破功。最近遇上類似議題,直覺要得回頭靠WinAPI Impersonation解決,之前曾寫過通用元件,擔心11年前Windows Vista/7時代的作品有點過時,就爬文找找更好的做法。
之前的變身做法是改變Thread的執(zhí)行身分,然而針對網(wǎng)路分享還有另一個WinAPI - WNetAddConnection2,可做到對多個網(wǎng)路分享使用不同登入身分。在stackoverflow找到有人分享把它包成搭配using使用的Context物件,符合我慣用的風(fēng)格,二話不說,按贊并寫文分享。
為方便使用,我再做了一層包裝,寫了一個NetworkCopier,將查目錄或復(fù)制檔案動作簡化成Copy(srcNetPath, targetPath, domain, userId, passwd)、DirFiles(srcNetPath, domain, userId, passwd),并支援預(yù)設(shè)帳密可省略輸入domain, userId, passwd;另外還有GetConnetionContext(path, domain, userId, passwd) 可取回NetworkConnection 物件方便用同一連線身分進行多項操作,若來源與目的屬不同網(wǎng)路分享則可套疊多重身分,寫成:
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的參數(shù)為\\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: 由設(shè)定檔、Registry 或 DB 取得帳號設(shè)定,密碼記得要加密保存
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("未設(shè)定預(yù)設(shè)登入身分");
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網(wǎng)路共享的詳細內(nèi)容,更多關(guān)于c# 訪問Windows網(wǎng)路共享的資料請關(guān)注腳本之家其它相關(guān)文章!
- c# WPF實現(xiàn)Windows資源管理器(附源碼)
- c# WPF中System.Windows.Interactivity的使用
- 如何使用C#修改本地Windows系統(tǒng)時間
- 使用C#實現(xiàn)Windows組和用戶管理的示例代碼
- c# 將Minio.exe注冊成windows服務(wù)
- windows系統(tǒng)下,如何在C#程序中自動安裝字體
- C#用Topshelf創(chuàng)建Windows服務(wù)的步驟分享
- C#創(chuàng)建簡單windows窗體應(yīng)用(加法器)
- C#開發(fā)windows服務(wù)實現(xiàn)自動從FTP服務(wù)器下載文件
- C#編寫Windows服務(wù)程序詳細步驟詳解(圖文)
- C# 屏蔽由于崩潰彈出的windows異常彈框
相關(guān)文章
測試框架nunit之a(chǎn)ssertion斷言使用詳解
NUnit是.Net平臺的測試框架,廣泛用于.Net平臺的單元測試和回歸測試中,下面我們用示例詳細學(xué)習(xí)一下他的使用方法2014-01-01
利用C#/VB.NET實現(xiàn)PPT轉(zhuǎn)換為HTML
利用PowerPoint可以很方便的呈現(xiàn)多媒體信息,且信息形式多媒體化,表現(xiàn)力強。但難免在某些情況下我們會需要將PowerPoint轉(zhuǎn)換為HTML格式,本文就為大家整理了轉(zhuǎn)換方法,希望對大家有所幫助2023-05-05

