检查当前用户是否为管理员

问题描述 投票:0回答:10

我的应用程序需要运行一些脚本,我必须确保运行它们的用户是管理员...使用 C# 执行此操作的最佳方法是什么?

c# windows-administration
10个回答
116
投票
using System.Security.Principal;

public static bool IsAdministrator()
{
    using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
    {
        WindowsPrincipal principal = new WindowsPrincipal(identity);
        return principal.IsInRole(WindowsBuiltInRole.Administrator);
    }
}

37
投票
return new WindowsPrincipal(WindowsIdentity.GetCurrent())
    .IsInRole(WindowsBuiltInRole.Administrator);

23
投票

您还可以调用 Windows API 来执行此操作:

[DllImport("shell32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsUserAnAdmin();

更一般地告诉您用户是否在提升的权限下运行。


16
投票

上面的 IsInRole 答案实际上是正确的:它确实检查当前用户是否具有管理员权限。 然而,

从 Windows Vista 开始,用户帐户控制 (UAC) 确定用户的权限。如果您是内置管理员组的成员,则会为您分配两个运行时访问令牌:标准用户访问令牌和管理员访问令牌。默认情况下,您具有标准用户角色。

(来自 MSDN,例如 https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogpermission(v=vs.110).aspx)

因此,IsInRole 默认情况下会考虑用户权限,因此该方法返回 false。仅当软件明确以管理员身份运行时才正确。

https://ayende.com/blog/158401/are-you-an-administrator中检查AD的另一种方法将检查用户名是否在管理员组中。

我将两者结合起来的完整方法是:

    public static bool IsCurrentUserAdmin(bool checkCurrentRole = true)
    {
        bool isElevated = false;

        using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
        {
            if (checkCurrentRole)
            {
                // Even if the user is defined in the Admin group, UAC defines 2 roles: one user and one admin. 
                // IsInRole consider the current default role as user, thus will return false!
                // Will consider the admin role only if the app is explicitly run as admin!
                WindowsPrincipal principal = new WindowsPrincipal(identity);
                isElevated = principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
            else
            {
                // read all roles for the current identity name, asking ActiveDirectory
                isElevated = IsAdministratorNoCache(identity.Name);
            }
        }

        return isElevated;
    }

    /// <summary>
    /// Determines whether the specified user is an administrator.
    /// </summary>
    /// <param name="username">The user name.</param>
    /// <returns>
    ///   <c>true</c> if the specified user is an administrator; otherwise, <c>false</c>.
    /// </returns>
    /// <seealso href="https://ayende.com/blog/158401/are-you-an-administrator"/>
    private static bool IsAdministratorNoCache(string username)
    {
        PrincipalContext ctx;
        try
        {
            Domain.GetComputerDomain();
            try
            {
                ctx = new PrincipalContext(ContextType.Domain);
            }
            catch (PrincipalServerDownException)
            {
                // can't access domain, check local machine instead 
                ctx = new PrincipalContext(ContextType.Machine);
            }
        }
        catch (ActiveDirectoryObjectNotFoundException)
        {
            // not in a domain
            ctx = new PrincipalContext(ContextType.Machine);
        }
        var up = UserPrincipal.FindByIdentity(ctx, username);
        if (up != null)
        {
            PrincipalSearchResult<Principal> authGroups = up.GetAuthorizationGroups();
            return authGroups.Any(principal =>
                                  principal.Sid.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid) ||
                                  principal.Sid.IsWellKnown(WellKnownSidType.AccountDomainAdminsSid) ||
                                  principal.Sid.IsWellKnown(WellKnownSidType.AccountAdministratorSid) ||
                                  principal.Sid.IsWellKnown(WellKnownSidType.AccountEnterpriseAdminsSid));
        }
        return false;
    }

对于管理员组中没有提升权限(启用 UAC)的用户,此方法 IsCurrentUserAdmin() 返回 !checkCurrentRole:如果 checkCurrentRole==false,则返回 true;如果 checkCurrentRole==true,则返回 false

如果您运行需要管理员权限的代码,请考虑 checkCurrentRole==true。否则,届时您将收到安全异常。 因此,正确的 IsInRole 逻辑。


8
投票

与这里的其他程序一样,我的程序没有以提升的方式运行,因此如果启用了 UAC,此代码将返回

false

private bool IsCurrentUserAnAdmin()
{
    var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
如果我的程序没有运行提升,并且用户是管理员,

@EricBDev 的答案

IsAdministratorNoCache
确实会返回
true
。然而,正如博客作者所说,它非常慢。

这是我的解决方案;它模拟

IsAdministratorNoCache
但速度很快:

private bool IsCurrentUserInAdminGroup()
{
    // https://learn.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows
    // S-1-5-32-544
    // A built-in group. After the initial installation of the operating system,
    // the only member of the group is the Administrator account.
    // When a computer joins a domain, the Domain Admins group is added to
    // the Administrators group. When a server becomes a domain controller,
    // the Enterprise Admins group also is added to the Administrators group.
    var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    var claims = principal.Claims;
    return (claims.FirstOrDefault(c => c.Value == "S-1-5-32-544") != null);
}

6
投票

David Ching 的答案很好 - 但给您留下了管理员组的硬编码 ID。这有点清楚了:

private bool IsCurrentUserInAdminGroup()
{
    var claims = new WindowsPrincipal(WindowsIdentity.GetCurrent()).Claims;
    var adminClaimID = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).Value;
    return claims.Any(c => c.Value == adminClaimID);
}

2
投票

只是想添加另一个解决方案;因为

IsInRole
并不总是有效。

  • 如果用户不是当前会话中指定 Windows 用户组的成员。
  • 管理员已在组策略设置中进行了更改
  • 角色参数被视为“区分大小写”方法。
  • 如果 XP 机器没有安装 .NET Framework 版本,它将无法工作。

根据您的需求是否需要支持旧系统;或者不确定您的客户如何物理管理您的系统。这是我实施的解决方案;为了灵活性和改变。

class Elevated_Rights
    {

        // Token Bool:
        private bool _level = false;

        #region Constructor:

        protected Elevated_Rights()
        {

            // Invoke Method On Creation:
            Elevate();

        }

        #endregion

        public void Elevate()
        {

            // Get Identity:
            WindowsIdentity user = WindowsIdentity.GetCurrent();

            // Set Principal
            WindowsPrincipal role = new WindowsPrincipal(user);

            #region Test Operating System for UAC:

            if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6)
            {

                // False:
                _level = false;

                // Todo: Exception/ Exception Log

            }

            #endregion

            else
            {

                #region Test Identity Not Null:

                if (user == null)
                {

                    // False:
                    _level = false;

                    // Todo: "Exception Log / Exception"

                }

                #endregion

                else
                {

                    #region Ensure Security Role:

                    if (!(role.IsInRole(WindowsBuiltInRole.Administrator)))
                    {

                        // False:
                        _level = false;

                        // Todo: "Exception Log / Exception"

                    }

                    else
                    {

                        // True:
                        _level = true;

                    }

                    #endregion


                } // Nested Else 'Close'

            } // Initial Else 'Close'

        } // End of Class.

所以上面的代码有一些构造;它实际上会测试用户是否使用 Vista 或更高版本。这样,如果客户使用的是多年前没有框架或测试版框架的 XP,它将允许您更改您想要执行的操作。

然后它将进行物理测试以避免帐户出现空值。

最后它将提供检查以验证用户确实处于正确的角色。

我知道问题已经得到解答;但我认为我的解决方案对于其他正在搜索 Stack 的人来说将是一个很好的补充。我对受保护构造函数的推理将允许您使用此类作为派生类,您可以控制实例化类时的状态。


0
投票

我必须确保运行它们的用户是管理员

如果您的应用程序必须以管理员权限运行,则更新其清单是正确的。

requestedExecutionlevel
设置为
requireAdminstrator


0
投票

这就是我的结局... 我强制我的应用程序以管理员模式运行。 为了做到这一点

1- 将

<ApplicationManifest>app.manifest</ApplicationManifest>
添加到您的
csproj
文件中。

MyProject.csproj

<Project Sdk="Microsoft.NET.Sdk">    
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <ApplicationManifest>app.manifest</ApplicationManifest>
  </PropertyGroup>    
</Project>

2- 将以下

app.manifest
文件添加到您的项目中。

app.manifest

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

0
投票
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, out TOKEN_ELEVATION TokenInformation, uint TokenInformationLength, out uint ReturnLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);


    static bool IsProcessElevated()
    {
        bool fIsElevated = false;
        IntPtr hToken = IntPtr.Zero;
        TOKEN_ELEVATION elevation;
        uint dwSize;

        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out hToken))
        {
            Debug.LogError("Failed to get Process Token: " + Marshal.GetLastWin32Error());
            goto Cleanup; // if Failed, we treat as False
        }

        if (!GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevation, out elevation, (uint)Marshal.SizeOf(typeof(TOKEN_ELEVATION)), out dwSize))
        {
            Debug.LogError("Failed to get Token Information: " + Marshal.GetLastWin32Error());
            goto Cleanup; // if Failed, we treat as False
        }

        fIsElevated = elevation.TokenIsElevated;

    Cleanup:
        if (hToken != IntPtr.Zero)
        {
            CloseHandle(hToken);
            hToken = IntPtr.Zero;
        }
        return fIsElevated;
    }

    const uint TOKEN_QUERY = 0x0008;

    enum TOKEN_INFORMATION_CLASS
    {
        TokenElevation = 20
    }

    struct TOKEN_ELEVATION
    {
        [MarshalAs(UnmanagedType.Bool)]
        public bool TokenIsElevated;
    }

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();
© www.soinside.com 2019 - 2024. All rights reserved.