当连接到当前用户(在我的例子中,是启用网络的服务用户)没有权限的网络共享时,必须提供名称和密码。
我知道如何用Win32函数(来自mpr.dll的WNet*家族)做到这一点,但想用. net(2.0)功能。
有哪些选择?
也许更多的信息会有所帮助:
用例是一个windows服务,而不是一个Asp。网络应用程序。 该服务运行在一个没有共享权限的帐户下。 客户端不知道共享所需的用户帐户。 客户端和服务器不是同一域的成员。
当连接到当前用户(在我的例子中,是启用网络的服务用户)没有权限的网络共享时,必须提供名称和密码。
我知道如何用Win32函数(来自mpr.dll的WNet*家族)做到这一点,但想用. net(2.0)功能。
有哪些选择?
也许更多的信息会有所帮助:
用例是一个windows服务,而不是一个Asp。网络应用程序。 该服务运行在一个没有共享权限的帐户下。 客户端不知道共享所需的用户帐户。 客户端和服务器不是同一域的成员。
当前回答
我非常喜欢马克·布兰克特的回答,所以我自己做了一个快速的执行。如果还有人急着要的话,这是:
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;
[MarshalAs(UnmanagedType.LPWStr)]
public string LocalName;
[MarshalAs(UnmanagedType.LPWStr)]
public string RemoteName;
[MarshalAs(UnmanagedType.LPWStr)]
public string Comment;
[MarshalAs(UnmanagedType.LPWStr)]
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
}
其他回答
你应该像这样添加一行:
<identity impersonate="true" userName="domain\user" password="****" />
在你的web.config中。
更多的信息。
这肯定是最愚蠢的方法,但它最近对我很有用,而且它简单得可笑。 当然,只能在Windows上使用。
Process.Start("CMDKEY", @"/add:""NetworkName"" /user:""Username"" /pass:""Password""");
然后,在尝试访问共享之前,可能需要使用WaitForExit()。
您可以在最后删除凭证,再次使用CMDKEY命令。
如果你不能创建一个本地有效的安全令牌,似乎你已经排除了所有选项栏Win32 API和WNetAddConnection*。
MSDN上关于WNet - PInvoke信息和连接到UNC路径的示例代码的大量信息:
http://www.pinvoke.net/default.aspx/mpr/WNetAddConnection2.html#
MSDN参考:
http://msdn.microsoft.com/en-us/library/aa385391 (VS.85) . aspx
7年后的今天,我面临着同样的问题,我想分享我的解决方案。
它是复制和粘贴准备好了:-)这里是:
步骤1
在你的代码中(当你需要使用权限做一些事情的时候)
ImpersonationHelper.Impersonate(domain, userName, userPassword, delegate
{
//Your code here
//Let's say file copy:
if (!File.Exists(to))
{
File.Copy(from, to);
}
});
步骤2
Helper文件起着神奇的作用
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;
namespace BlaBla
{
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle()
: base(true)
{
}
[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
public class ImpersonationHelper
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private extern static bool CloseHandle(IntPtr handle);
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public static void Impersonate(string domainName, string userName, string userPassword, Action actionToExecute)
{
SafeTokenHandle safeTokenHandle;
try
{
const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(userName, domainName, userPassword,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
out safeTokenHandle);
//Facade.Instance.Trace("LogonUser called.");
if (returnValue == false)
{
int ret = Marshal.GetLastWin32Error();
//Facade.Instance.Trace($"LogonUser failed with error code : {ret}");
throw new System.ComponentModel.Win32Exception(ret);
}
using (safeTokenHandle)
{
//Facade.Instance.Trace($"Value of Windows NT token: {safeTokenHandle}");
//Facade.Instance.Trace($"Before impersonation: {WindowsIdentity.GetCurrent().Name}");
// Use the token handle returned by LogonUser.
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
//Facade.Instance.Trace($"After impersonation: {WindowsIdentity.GetCurrent().Name}");
//Facade.Instance.Trace("Start executing an action");
actionToExecute();
//Facade.Instance.Trace("Finished executing an action");
}
}
//Facade.Instance.Trace($"After closing the context: {WindowsIdentity.GetCurrent().Name}");
}
}
catch (Exception ex)
{
//Facade.Instance.Trace("Oh no! Impersonate method failed.");
//ex.HandleException();
//On purpose: we want to notify a caller about the issue /Pavel Kovalev 9/16/2016 2:15:23 PM)/
throw;
}
}
}
}
一种可行的方法是使用WindowsIdentity。模拟(并更改线程主体)成为所需的用户,如下所示。回到p/invoke,不过,恐怕……
另一个厚脸皮的(同样不理想的)选择可能是生成一个流程来完成这项工作……ProcessStartInfo接受. username, . password和. domain。
最后-也许在一个有权限的专用帐户中运行服务?(删除,因为你已经澄清这不是一个选项)。