[英]How to get a Unique ID for the current user's logon session in windows - c#
我需要获取一个唯一标识当前Windows用户登录会话的值。 这是用于winforms应用程序,而不是ASP.NET。 我将从多个进程中检索它,因此在同一登录会话中检索到它时,它需要返回相同的值。 在所有用户会话的持续时间内,它仅需要在当前计算机上是唯一的-例如,直到下次重新启动计算机为止。
我认为Windows登录ID是正确的事情,但是要检索它似乎有些麻烦。 还有其他方法或更简单的方法可以做到这一点吗?
我将使用ID将其包含在命名管道服务的地址中,以在计算机上运行的两个进程之间进行通信。 我想包括登录ID,以避免在有多个用户登录时可能发生冲突,包括同一用户的多个会话。
获取会话ID的最简单方法是查看Process.SessionId属性:
System.Diagnostics.Process.GetCurrentProcess().SessionId
该值与GetTokenInformation(...,TokenSessionId,...)返回的值相同。
注意:您应该记住的一件事是,会话ID不是登录ID 。 例如,在Win7提升的进程中,在同一用户下在同一会话中启动的提升进程将具有不同的LogonId(复制到非提升的LogonId),但是将具有相同的SessionId。 即使使用RunAs显式指定同一用户的凭据的运行非提升过程,也会创建新的Logon Sesison ID。 例如,当您映射网络驱动器时,这种行为具有含义。 从Vista开始,即使进程在同一会话中和同一用户下运行,具有一个令牌LogonId的进程也不会看到与另一个LogonId映射的网络驱动程序。
以下是示例应用程序,您可以在不同的会话/信条上启动以查看它们之间的区别:
using System;
using System.Runtime.InteropServices;
namespace GetCurrentSessionId
{
class Program
{
enum TokenInformationClass
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin
}
enum TokenType
{
TokenPrimary = 1,
TokenImpersonation
}
enum SecurityImpersonationLevel
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
[StructLayout(LayoutKind.Sequential)]
struct TokenStatistics
{
public Int64 TokenId;
public Int64 AuthenticationId;
public Int64 ExpirationTime;
public TokenType TokenType;
public SecurityImpersonationLevel ImpersonationLevel;
public Int32 DynamicCharged;
public Int32 DynamicAvailable;
public Int32 GroupCount;
public Int32 PrivilegeCount;
public Int64 ModifiedId;
}
struct TokenOrigin
{
public Int64 OriginatingLogonSession;
}
[DllImport("advapi32.dll", EntryPoint = "GetTokenInformation", SetLastError = true)]
static extern bool GetTokenInformation(
IntPtr tokenHandle,
TokenInformationClass tokenInformationClass,
IntPtr tokenInformation,
int tokenInformationLength,
out int ReturnLength);
public const int ERROR_INSUFFICIENT_BUFFER = 0x7a;
static void Main(string[] args)
{
try
{
Console.WriteLine("Session Id: {0}", System.Diagnostics.Process.GetCurrentProcess().SessionId);
IntPtr tokenInfo;
bool result;
int infoSize;
IntPtr hToken = System.Security.Principal.WindowsIdentity.GetCurrent().Token;
result = GetTokenInformation(hToken, TokenInformationClass.TokenStatistics, IntPtr.Zero, 0, out infoSize);
if (!result && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
tokenInfo = Marshal.AllocHGlobal(infoSize);
result = GetTokenInformation(hToken, TokenInformationClass.TokenStatistics, tokenInfo, infoSize, out infoSize);
if (result)
{
TokenStatistics tokenStats = (TokenStatistics)Marshal.PtrToStructure(tokenInfo, typeof(TokenStatistics));
Console.WriteLine("LogonId: 0x{0:X16}", tokenStats.AuthenticationId);
}
else
{
Console.Error.WriteLine("LogonId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
}
Marshal.FreeHGlobal(tokenInfo);
}
else
{
Console.Error.WriteLine("LogonId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
}
tokenInfo = Marshal.AllocHGlobal(sizeof (Int32));
result = GetTokenInformation(hToken, TokenInformationClass.TokenSessionId, tokenInfo, sizeof (Int32), out infoSize);
if (result)
{
int tokenSessionId = Marshal.ReadInt32(tokenInfo);
Console.WriteLine("TokenSessionId: {0}", tokenSessionId);
}
else
{
Console.Error.WriteLine("TokenSessionId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
}
Marshal.FreeHGlobal(tokenInfo);
result = GetTokenInformation(hToken, TokenInformationClass.TokenOrigin, IntPtr.Zero, 0, out infoSize);
if (!result && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
tokenInfo = Marshal.AllocHGlobal(infoSize);
result = GetTokenInformation(hToken, TokenInformationClass.TokenOrigin, tokenInfo, infoSize, out infoSize);
if (result)
{
TokenOrigin tokenOrigin = (TokenOrigin) Marshal.PtrToStructure(tokenInfo, typeof (TokenOrigin));
Console.WriteLine("OriginatingSessionId: 0x{0:X16}", tokenOrigin.OriginatingLogonSession);
}
else
{
Console.WriteLine("OriginatingSessionId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
}
Marshal.FreeHGlobal(tokenInfo);
}
else
{
Console.WriteLine("OriginatingSessionId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
}
Console.WriteLine("Press any key...");
Console.ReadKey();
}
catch (Exception ex)
{
Console.Error.WriteLine("Unexpected error: {0}", ex);
Console.ReadKey();
}
}
}
}
据我了解,您需要的是:
SID:S-1-5-5-XY名称:登录会话说明:登录会话。 这些SID的X和Y值在每个会话中都不同。
Windows操作系统中的众所周知的安全标识符http://support.microsoft.com/kb/243330
有人在这里要求类似的东西:
他们在那里有一个很好的答案,但我想添加自己的答案
这是我的解决方案:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace TestLogonSid
{
public partial class Form1 : Form
{
private delegate bool EnumDesktopProc(string lpszDesktop, IntPtr lParam);
public Form1()
{
InitializeComponent();
}
private void button1_Click_1(object sender, EventArgs e)
{
this.textBox1.Text = GetLogonSid.getLogonSid();
}
}
public class GetLogonSid
{
//The SID structure that identifies the user that is currently associated with the specified object.
//If no user is associated with the object, the value returned in the buffer pointed to by lpnLengthNeeded is zero.
//Note that SID is a variable length structure.
//You will usually make a call to GetUserObjectInformation to determine the length of the SID before retrieving its value.
private const int UOI_USER_SID = 4;
//GetUserObjectInformation function
//Retrieves information about the specified window station or desktop object.
[DllImport("user32.dll")]
static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [MarshalAs(UnmanagedType.LPArray)] byte[] pvInfo, int nLength, out uint lpnLengthNeeded);
//GetThreadDesktop function
//Retrieves a handle to the desktop assigned to the specified thread.
[DllImport("user32.dll")]
private static extern IntPtr GetThreadDesktop(int dwThreadId);
//GetCurrentThreadId function
//Retrieves the thread identifier of the calling thread.
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
//ConvertSidToStringSid function
//The ConvertSidToStringSid function converts a security identifier (SID) to a string format suitable for display, storage, or transmission.
//To convert the string-format SID back to a valid, functional SID, call the ConvertStringSidToSid function.
[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool ConvertSidToStringSid(
[MarshalAs(UnmanagedType.LPArray)] byte[] pSID,
out IntPtr ptrSid);
/// <summary>
/// The getLogonSid function returns the Logon Session string
/// </summary>
/// <returns></returns>
public static string getLogonSid()
{
string sidString = "";
IntPtr hdesk = GetThreadDesktop(GetCurrentThreadId());
byte[] buf = new byte[100];
uint lengthNeeded;
GetUserObjectInformation(hdesk, UOI_USER_SID, buf, 100, out lengthNeeded);
IntPtr ptrSid;
if (!ConvertSidToStringSid(buf, out ptrSid))
throw new System.ComponentModel.Win32Exception();
try
{
sidString = Marshal.PtrToStringAuto(ptrSid);
}
catch
{
}
return sidString;
}
}
}
您可以尝试Environment.UserDomainName
和Environment.UserName
为了确保每个用户会话的唯一ID,我猜您将不得不使用您提到的痛苦的方法- 如何在C#中获取登录SID 。
如果我对您的理解正确,则可以生成一个GUID
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.