public class LogonUserNS { [DllImport("advapi32.dll", SetLastError=true)] public extern static bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)] public extern static bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); public static void Main(string[] args) { IntPtr tokenHandle = new IntPtr(0); IntPtr dupeTokenHandle = new IntPtr(0); try { if (args.Length < 3) { Console.WriteLine("Usage: DomainName UserName Password"); return; } // args[0] - DomainName // args[1] - UserName // args[2] - Password const int LOGON32_PROVIDER_DEFAULT = 0; //This parameter causes LogonUser to create a primary token. const int LOGON32_LOGON_INTERACTIVE = 2; const int SecurityImpersonation = 2; tokenHandle = IntPtr.Zero; dupeTokenHandle = IntPtr.Zero; // Call LogonUser to obtain an handle to an access token. bool returnValue = LogonUser(args[1], args[0], args[2], LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);
if (false == returnValue) { Console.WriteLine("LogonUser failed with error code : {0}", Marshal.GetLastWin32Error()); return; } // Check the identity. Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name);
// The token that is passed to the following constructor must // be a primary token to impersonate. WindowsIdentity newId = new WindowsIdentity(tokenHandle); WindowsImpersonationContext impersonatedUser = newId.Impersonate(); // Check the identity. Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
Process.Start("CMD", @"/c net use \\COMPUTERNAME /user:USERNAME " + "PASSWORD") 启动的是一个新的进程,和你现在使用的进程不是同一个。你当前的进程暂时只拥有启动用户的身份识别。 上面的代码应该没有作用,因为它是登陆到本地计算机,而不是远程。;) 呵呵,失误。 你等一下,我帮你看看如何登陆远程计算机的资料。不过,建议使用AD机制来做,安全性、可管理性更好一些。 你可以在AD创建一个专门的帐号,然后以这个帐号身份启动你的程序;AD中授权这个帐号可以访问目标计算机,一切就OK了。
The LogonUser function attempts to log a user on to the local computer. The local computer is the computer from which LogonUser was called. You cannot use LogonUser to log on to a remote computer. You specify the user with a user name and domain, and authenticate the user with a clear-text password. If the function succeeds, you receive a handle to a token that represents the logged-on user. You can then use this token handle to impersonate the specified user, or in most cases, to create a process running in the context of the specified user.
我写了如下代码,结果能连接上远程计算机,但还是不能访问消息队列,问题在哪呢? public class class1 { [StructLayout(LayoutKind.Sequential)] public struct NetResource { public int dwScope; public int dwType; public int dwDisplayType; public int dwUsage; public string lpLocalName; public string lpRemoteName; public string lpComment; public string lpProvider; } const int RESOURCETYPE_ANY=0x00000000;
[DllImport("mpr.dll")] static extern int WNetAddConnection2(ref NetResource lpNetResource,string lpPassword,string lpUserName,int dwFlags);private void button1_Click(object sender, System.EventArgs e) { try { string name = "administrator"; string passwd = "123456"; string ipc = "\\\\siislq"; NetResource nr = new NetResource(); nr.lpLocalName = null; nr.lpProvider = null; nr.dwType = RESOURCETYPE_ANY; nr.lpRemoteName = ipc; int ret = WNetAddConnection2(ref nr,passwd,name,0); if (ret != 0) { MessageBox.Show(ret.ToString()); } MessageQueue[] m = MessageQueue.GetPrivateQueuesByMachine("siislq" MessageBox.Show(m.Length.ToString()); } catch(MessageQueueException ex) { MessageBox.Show(ex.ToString()); } }
{
[DllImport("advapi32.dll", SetLastError=true)]
public extern static bool LogonUser(String lpszUsername, String lpszDomain,
String lpszPassword, int dwLogonType,
int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); public static void Main(string[] args)
{
IntPtr tokenHandle = new IntPtr(0);
IntPtr dupeTokenHandle = new IntPtr(0); try
{
if (args.Length < 3)
{
Console.WriteLine("Usage: DomainName UserName Password");
return;
}
// args[0] - DomainName
// args[1] - UserName
// args[2] - Password const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
const int SecurityImpersonation = 2; tokenHandle = IntPtr.Zero;
dupeTokenHandle = IntPtr.Zero; // Call LogonUser to obtain an handle to an access token.
bool returnValue = LogonUser(args[1], args[0], args[2],
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
if (false == returnValue)
{
Console.WriteLine("LogonUser failed with error code : {0}",
Marshal.GetLastWin32Error());
return;
} // Check the identity.
Console.WriteLine("Before impersonation: "
+ WindowsIdentity.GetCurrent().Name);
// The token that is passed to the following constructor must
// be a primary token to impersonate.
WindowsIdentity newId = new WindowsIdentity(tokenHandle);
WindowsImpersonationContext impersonatedUser = newId.Impersonate(); // Check the identity.
Console.WriteLine("After impersonation: "
+ WindowsIdentity.GetCurrent().Name);
// Stop impersonating.
impersonatedUser.Undo(); // Check the identity.
Console.WriteLine("After Undo: " + WindowsIdentity.GetCurrent().Name);
// Free the tokens.
if (tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
if (dupeTokenHandle != IntPtr.Zero)
CloseHandle(dupeTokenHandle);
}
catch(Exception ex)
{
Console.WriteLine("Exception occurred. " + ex.Message);
}
}
}
关于登陆到另一台计算的方法,你可以参看MSDN中的这个连接:
ms-help://MS.MSDNQTR.2003FEB.2052/enu_kbnetframeworkkb/en-us/netframeworkkb/Q319615.htm同一个工作组中的计算机之间,并不存在AD那样的权限控制信息。你不能保证在同一个组中,你的机器就拥有对另一台机器的访问权限。AD则不一样,可以保证运行程序的域用户可以或者不可以访问域内其他计算机上的资源。
为什么呢?
你可以在两个机器上建立用户名和密码一致的用户,进行测试。
不过正如你所说,用同名同密码登录就不会产生异常,但应该怎么解决呢?程序不可能只使用在同一个用户名的电脑上。
启动的是一个新的进程,和你现在使用的进程不是同一个。你当前的进程暂时只拥有启动用户的身份识别。
上面的代码应该没有作用,因为它是登陆到本地计算机,而不是远程。;) 呵呵,失误。
你等一下,我帮你看看如何登陆远程计算机的资料。不过,建议使用AD机制来做,安全性、可管理性更好一些。
你可以在AD创建一个专门的帐号,然后以这个帐号身份启动你的程序;AD中授权这个帐号可以访问目标计算机,一切就OK了。
这上面的信息应该足以解决你的问题了。使用样例代码在这里
ms-help://MS.MSDNQTR.2003FEB.2052/wnet/wnet/adding_a_network_connection.htm执行GetPrivateQueuesByMachine前,WNetAddConnection2先。
public class class1
{
[StructLayout(LayoutKind.Sequential)]
public struct NetResource
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
public string lpLocalName;
public string lpRemoteName;
public string lpComment;
public string lpProvider;
} const int RESOURCETYPE_ANY=0x00000000;
[DllImport("mpr.dll")]
static extern int WNetAddConnection2(ref NetResource lpNetResource,string lpPassword,string lpUserName,int dwFlags);private void button1_Click(object sender, System.EventArgs e)
{
try
{
string name = "administrator";
string passwd = "123456";
string ipc = "\\\\siislq";
NetResource nr = new NetResource();
nr.lpLocalName = null;
nr.lpProvider = null;
nr.dwType = RESOURCETYPE_ANY;
nr.lpRemoteName = ipc;
int ret = WNetAddConnection2(ref nr,passwd,name,0); if (ret != 0)
{
MessageBox.Show(ret.ToString());
} MessageQueue[] m = MessageQueue.GetPrivateQueuesByMachine("siislq"
MessageBox.Show(m.Length.ToString());
}
catch(MessageQueueException ex)
{
MessageBox.Show(ex.ToString());
}
}
MessageQueue.GetPrivateQueuesByMachine("siislq");
Sorry,走了这么多弯路。也许解决方法应该是这样子的:
到计算机管理器中,找到消息队列节点,打开私有队列中你的消息队列,
它的属性中,有关于访问权限的设定。你设置为Everyone就可以了。