将文件移至网络共享(通过模拟)C#
我一直在使用 C# (.net4) 开发一个项目。项目几乎允许人们将文件从本地计算机上传到网络共享。
网络共享受到保护。它只能由在活动目录中创建的名为“proxy”的用户访问。
我做了一些研究,发现了我用来模仿的课程。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace Datacom.CorporateSys.Utilities
{
public class ImpersonateUser
{
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
WindowsImpersonationContext impersonationContext;
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
private string p;
private string p_2;
private string p_3;
private String UserName
{
set;
get;
}
private String Domain
{
set;
get;
}
private String Password
{
set;
get;
}
/// <summary>
/// Impersonates the user.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="domain">The domain.</param>
/// <param name="password">The password.</param>
public ImpersonateUser(string userName, string domain, string password)
{
UserName = userName;
Domain = domain;
Password = password;
}
/// <summary>
/// Impersonates the valid user.
/// </summary>
/// <returns></returns>
public bool impersonateValidUser()
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(UserName, Domain, Password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
/// <summary>
/// Undoes the impersonation.
/// </summary>
public void undoImpersonation()
{
impersonationContext.Undo();
}
}
}
注意:根据记忆,我想我在 msdn 上找到了这个示例。
这就是我尝试将文件从本地路径移动到网络的方法
if (imp.impersonateValidUser())
{
System.IO.File.Copy(local_file, server_file, true);
imp.undoImpersonation();
}
else
{
throw new Exception("Unable to impersonate for uploading file.");
}
,它有效!我从来没有遇到过模仿问题 - 永远不会抛出异常。它工作正常并将文件上传到服务器。但是,当我开始进行更多测试时,我发现如果代理用户未登录到服务器(通常我打开 RDS 登录并退出 - 无需注销)。
我得到了不同的异常 - 网络路径未找到异常,并且仅当我刚刚重新启动服务器并且“代理”未登录时才会发生。
我的第一个想法是模拟类有问题,然而,当它确实工作时,它会模仿得很好(即文件拥有代理用户的所有权)。然后我想也许需要登录“代理”,以便操作系统可以使用其权限来实际访问 \server\uploads
我现在非常迷失,不知道如何解决它。 请注意:我无法控制服务器。服务器是win2k8,安装了桌面体验(否则我无法访问任何网络位置)。
谢谢!
I have been working on a project in C# (.net4). Project pretty much allows people to upload files from their local machine to a network share.
Network share is secured. It is only accessible by user called "proxy" which is created in active directory.
I did some research and I found this class which I used for impersonation.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace Datacom.CorporateSys.Utilities
{
public class ImpersonateUser
{
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
WindowsImpersonationContext impersonationContext;
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
private string p;
private string p_2;
private string p_3;
private String UserName
{
set;
get;
}
private String Domain
{
set;
get;
}
private String Password
{
set;
get;
}
/// <summary>
/// Impersonates the user.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="domain">The domain.</param>
/// <param name="password">The password.</param>
public ImpersonateUser(string userName, string domain, string password)
{
UserName = userName;
Domain = domain;
Password = password;
}
/// <summary>
/// Impersonates the valid user.
/// </summary>
/// <returns></returns>
public bool impersonateValidUser()
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(UserName, Domain, Password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
/// <summary>
/// Undoes the impersonation.
/// </summary>
public void undoImpersonation()
{
impersonationContext.Undo();
}
}
}
Note: From memory I think I found this as an example on msdn.
This is how I try to move a file from local path to network
if (imp.impersonateValidUser())
{
System.IO.File.Copy(local_file, server_file, true);
imp.undoImpersonation();
}
else
{
throw new Exception("Unable to impersonate for uploading file.");
}
And it works! I never have issues with impersonation - exception never gets thrown. It works fine and uploads files to the server. However, when I started testing a bit more I found that if proxy user is not logged in to the server (normally I open RDS login and quit - without logging out).
I get different exception - network path not found exception and it only occurs when I have just restarted the server and "proxy" is not logged in.
My first thought was that there is something wrong with impersonation class, however it impersonates fine when it does work (ie. files have ownership of proxy user). Then I thought that maybe "proxy" needs to be logged in so OS can use its permissions to actually access \server\uploads
I'm extremely lost now, not sure how to solve it.
Please note: I have no control over the server. Server is win2k8 with desktop experience installed (otherwise i cant access any network locations).
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
授予代理帐户访问权限“作为批处理作业登录”并使用
`LOGON32_LOGON_BATCH
而不是交互式登录。Grant the proxy account access right "Log on as a batch Job" and use
`LOGON32_LOGON_BATCH
instead of interactive logon.