我的应用程序需要运行一些脚本,并且我必须确保运行它们的用户是管理员...使用C#做到这一点的最佳方法是什么?
Answers:
using System.Security.Principal;
public static bool IsAdministrator()
{
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
{
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
return new WindowsPrincipal(WindowsIdentity.GetCurrent())
.IsInRole(WindowsBuiltInRole.Administrator);
您也可以调用Windows API来执行此操作:
[DllImport("shell32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsUserAnAdmin();
更笼统地告诉您用户是否在提升的权限下运行。
上面关于IsInRole的答案实际上是正确的:它会检查当前用户是否具有管理员权限。然而,
从Windows Vista开始,用户帐户控制(UAC)确定用户的特权。如果您是“内置管理员”组的成员,则会为您分配两个运行时访问令牌:标准用户访问令牌和管理员访问令牌。默认情况下,您处于标准用户角色。
(来自MSDN,例如https://msdn.microsoft.com/zh-cn/library/system.diagnostics.eventlogpermission(v=vs.110).aspx)
因此,默认情况下,IsInRole将考虑用户权限,因此该方法返回false。仅当软件以管理员身份明确运行时才为true。
在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逻辑。
只是以为我会添加另一个解决方案;因为IsInRole
并非总是有效。
如果需要支持较早的系统,请根据需要进行;或者不确定您的客户端如何物理管理系统。这是我实现的解决方案;以获得灵活性和变更性。
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而不具有框架或Beta框架,它将使您能够更改自己想做的事情。
然后,它将进行物理测试以避免该帐户的空值。
然后,最后它将提供检查以验证用户确实扮演了正确的角色。
我知道问题已经回答;但是我认为对于正在搜索Stack的其他任何人,我的解决方案都将是该页面的绝佳补充。我在Protected Constructor背后的理由是,您可以将此类用作派生类,从而可以控制实例化该类时的状态。
这就是我最终的方式...我强迫我的应用以管理员模式运行。去做这个
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
文件添加到您的项目。
应用清单
<?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>