如何在 Windows 中获取当前用户登录会话的唯一 ID - c#

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6061143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 16:52:39  来源:igfitidea点击:

How to get a Unique ID for the current user's logon session in windows - c#

c#.netwindows

提问by Rory

I need to get a value that uniquely identifies the current windows user's logon session. This is for a winforms app, not ASP.NET. I'll be retrieving this from within multiple processes so it needs to return the same value when retrieved within the same logon session. It only needs to be unique on the current machine for the duration of all user sessions - e.g. until the machine is next restarted.

我需要获得一个唯一标识当前 Windows 用户登录会话的值。这是一个 winforms 应用程序,而不是 ASP.NET。我将从多个进程中检索它,因此在同一登录会话中检索时它需要返回相同的值。它只需要在所有用户会话期间在当前机器上是唯一的——例如,直到机器下次重新启动。

I think the Windows Logon Idis the right thing, but seems a bit of a pain to retrieve. Is there anything else or any easier way to get this?

我认为Windows 登录 ID是正确的,但检索起来似乎有点麻烦。有没有其他方法或更简单的方法来获得它?

I'll be using the ID to include in an address of a named pipes service to communicate between two processes running on the machine. I want to include the Logon Id to avoid conflicts when there are multiple users logged in, including perhaps multiple sessions of the same user.

我将使用 ID 包含在命名管道服务的地址中,以便在机器上运行的两个进程之间进行通信。我想包括登录 ID 以避免在有多个用户登录时发生冲突,可能包括同一用户的多个会话。

回答by mistika

The easiest way to get Session Id is to look at Process.SessionIdproperty:

获取 Session Id 的最简单方法是查看Process.SessionId属性:

System.Diagnostics.Process.GetCurrentProcess().SessionId

The value is the same as returned by GetTokenInformation(...,TokenSessionId,...).

该值与GetTokenInformation(...,TokenSessionId,...)返回的值相同。

Note:One thing you should keep in mind is that Session Id is not a Logon Id. For example, on Win7 elevated process launched under the same user in the same session will have different LogonId (copmaring to non-elevated one), but will have the same SessionId. Even runniung non-elevated process with RunAs explicitly specifying credentials of the same user will create new Logon Sesison Id. Such behavior has meaning, for example, when you map network drives. Since Vista, a process with one token LogonId will not see network dirves mapped with another LogonId, even if processes are running in the same session and under same user.

注意:您应该记住的一件事是 Session Id 不是Logon Id。例如,在同一会话中同一用户下启动的 Win7 提升进程将具有不同的 LogonId(与非提升的相比),但将具有相同的 SessionId。即使使用 RunAs 明确指定同一用户的凭据的 runniung non-elevated 进程也会创建新的 Logon Sesison Id。例如,当您映射网络驱动器时,这种行为是有意义的。从 Vista 开始,具有一个令牌 LogonId 的进程不会看到映射到另一个 LogonId 的网络目录,即使进程在同一会话中以同一用户身份运行。

Below is the sample app that you can launch on different sessions/creds to see the difference:

下面是示例应用程序,您可以在不同的会话/凭据上启动以查看差异:

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();
            }
        }
    }
}

回答by ccarmona1981

As I understand, what you need is this:

据我了解,您需要的是:

SID: S-1-5-5-X-Y Name: Logon Session Description: A logon session. The X and Y values for these SIDs are different for each session.

SID:S-1-5-5-XY 名称:登录会话 描述:登录会话。这些 SID 的 X 和 Y 值对于每个会话都不同。

Well-known security identifiers in Windows operating systems http://support.microsoft.com/kb/243330

Windows 操作系统中众所周知的安全标识符 http://support.microsoft.com/kb/243330

Somebody asked for something similar here:

有人在这里要求类似的东西:

How to get the logon SID in C#

如何在C#中获取登录SID

They have a good answer there, but I want to add my own

他们有一个很好的答案,但我想添加我自己的

This is my solution:

这是我的解决方案:

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;
        }

    }
}

回答by YetAnotherUser

You can try Environment.UserDomainName& Environment.UserName

你可以试试Environment.UserDomainName&Environment.UserName

To ensure a unique id for each user sessionI guess you'll have to use the painful method you mentioned - How to get the logon SID in C#.

为了确保每个用户会话唯一 ID,我想您将不得不使用您提到的痛苦方法 -如何在 C# 中获取登录 SID

回答by Darren Young

If I understand you correctly you can generate a GUID

如果我理解正确,您可以生成一个GUID