ASP.NET 應用程式需存取遠端共享資料夾(UNC 路徑)時,可透過 Windows API 進行使用者模擬(Impersonation),取得具備網路權限的 Token 執行檔案操作。
public class IdentityScope : IDisposable {
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
extern static bool CloseHandle(IntPtr handle);
[DllImport("Advapi32.DLL")]
static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("Advapi32.DLL")]
static extern bool RevertToSelf();
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_NEWCREDENTIALS = 9; // 網路憑證類型
private bool disposed;
public IdentityScope(string sUsername, string sDomain, string sPassword) {
IntPtr pExistingTokenHandle = IntPtr.Zero;
IntPtr pDuplicateTokenHandle = IntPtr.Zero;
try {
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
LOGON32_LOGON_NEWCREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);
if (bImpersonated) {
if (!ImpersonateLoggedOnUser(pExistingTokenHandle)) {
int nErrorCode = Marshal.GetLastWin32Error();
throw new Exception("ImpersonateLoggedOnUser error; Code=" + nErrorCode);
}
} else {
int nErrorCode = Marshal.GetLastWin32Error();
throw new Exception("LogonUser error; Code=" + nErrorCode);
}
} finally {
if (pExistingTokenHandle != IntPtr.Zero) CloseHandle(pExistingTokenHandle);
if (pDuplicateTokenHandle != IntPtr.Zero) CloseHandle(pDuplicateTokenHandle);
}
}
protected virtual void Dispose(bool disposing) {
if (!disposed) {
RevertToSelf();
disposed = true;
}
}
public void Dispose() { Dispose(true); }
}
// 第二個參數為域名或目標機器 IP
using (IdentityScope c = new IdentityScope("administrator", "192.168.0.1", "11111")) {
string[] filelist = System.IO.Directory.GetDirectories(@"\\192.168.0.1\folderName");
// 執行檔案讀寫操作...
}
若不想寫程式碼,可在 web.config 直接啟用模擬:
<identity impersonate="true" userName="伺服器用戶名" password="伺服器密碼" />
若需防止使用者透過複製 URL 存取無權限頁面,建議建立「頁面-用戶」關聯表,於 Page_Load 或攔截器中驗證權限。