내 응용 프로그램에서 일부 스크립트를 실행해야하고 스크립트를 실행하는 사용자가 관리자인지 확인해야합니다. C #을 사용하여이 작업을 수행하는 가장 좋은 방법은 무엇입니까?
답변:
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/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 논리입니다.
다른 솔루션을 추가 할 것이라고 생각했습니다. 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를 사용하는 경우 원하는 작업을 변경할 수 있습니다.
그런 다음 계정의 null 값을 피하기 위해 물리적으로 테스트합니다.
그런 다음 마지막으로 사용자가 실제로 적절한 역할에 있는지 확인하는 검사를 제공합니다.
나는 질문에 대한 답을 알고 있습니다. 하지만 내 솔루션이 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
프로젝트에 아래 파일을 추가하십시오 .
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>