Как получить уникальный идентификатор для сеанса входа текущего пользователя в Windows - C#
Мне нужно получить значение, которое однозначно определяет сеанс входа текущего пользователя Windows. Это для приложения winforms, а не ASP.NET. Я получу это из нескольких процессов, поэтому оно должно возвращать одно и то же значение при получении в течение одного сеанса входа. Он должен быть уникальным только на текущем компьютере в течение всех сеансов пользователя - например, до следующего перезапуска компьютера.
Я думаю, что Windows Logon Id - это то, что нужно, но мне кажется, что восстановить его немного сложно. Есть ли что-нибудь еще или более простой способ получить это?
Я буду использовать идентификатор для включения в адрес службы именованных каналов для связи между двумя процессами, работающими на машине. Я хочу включить идентификатор входа в систему, чтобы избежать конфликтов, когда вошли несколько пользователей, в том числе, возможно, несколько сеансов одного и того же пользователя.
4 ответа
Как я понимаю, что вам нужно это:
SID: S-1-5-5-XY Имя: сеанс входа в систему Описание: сеанс входа в систему. Значения X и Y для этих SID различны для каждого сеанса.
Известные идентификаторы безопасности в операционных системах Windows http://support.microsoft.com/kb/243330
Кто-то просил что-то подобное здесь:
Как получить SID для входа в систему в C#
У них там хороший ответ, но я хочу добавить свой
Это мое решение:
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;
}
}
}
Самый простой способ получить идентификатор сессии - посмотреть на свойство Process.SessionId:
System.Diagnostics.Process.GetCurrentProcess().SessionId
Значение совпадает с возвращаемым GetTokenInformation (..., TokenSessionId,...).
Примечание. Следует иметь в виду, что идентификатор сеанса не является идентификатором входа. Например, в Win7 процесс с повышенными правами, запущенный одним и тем же пользователем в одном сеансе, будет иметь другой LogonId (сопоставимый с не повышенным), но будет иметь тот же SessionId. Даже запуск процесса без повышенных прав с RunAs, явно указывающими учетные данные одного и того же пользователя, создаст новый идентификатор входа в систему. Такое поведение имеет значение, например, когда вы подключаете сетевые диски. Начиная с 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();
}
}
}
}
Ты можешь попробовать Environment.UserDomainName
& Environment.UserName
Для обеспечения уникального идентификатора для каждого пользовательского сеанса, я думаю, вам придется использовать болезненный метод, который вы упомянули - Как получить SID для входа в систему в C#.