Moja aplikacja musi uruchamiać jakieś skrypty i muszę mieć pewność, że użytkownik, który je uruchamia, jest administratorem ... Jak najlepiej to zrobić za pomocą C #?
Odpowiedzi:
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);
Możesz również wywołać interfejs API systemu Windows, aby to zrobić:
[DllImport("shell32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsUserAnAdmin();
który bardziej ogólnie mówi, czy użytkownik działa z podwyższonymi uprawnieniami.
Powyższe odpowiedzi z IsInRole są w rzeczywistości poprawne: sprawdza, czy bieżący użytkownik ma uprawnienia administratora. Jednak,
Począwszy od systemu Windows Vista, Kontrola konta użytkownika (UAC) określa uprawnienia użytkownika. Jeśli jesteś członkiem grupy Wbudowani administratorzy, zostaną Ci przypisane dwa tokeny dostępu w czasie wykonywania: token dostępu użytkownika standardowego i token dostępu administratora. Domyślnie jesteś w standardowej roli użytkownika.
(z MSDN, np. https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogpermission(v=vs.110).aspx )
Dlatego IsInRole domyślnie uwzględni uprawnienia użytkownika, a zatem metoda zwróci wartość false. Prawda tylko wtedy, gdy oprogramowanie jest jawnie uruchamiane jako administrator.
Druga metoda sprawdzania AD w https://ayende.com/blog/158401/are-you-an-administrator sprawdzi, czy nazwa użytkownika znajduje się w grupie administratorów.
Moja kompletna metoda łącząca oba to:
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;
}
Dla użytkownika w grupie administracyjnej bez podwyższonych uprawnień (włączone UAC), ta metoda IsCurrentUserAdmin () zwraca! CheckCurrentRole: true, jeśli checkCurrentRole == false, ale false if checkCurrentRole == true
Jeśli uruchamiasz kod, który WYMAGA uprawnień administratora, weź pod uwagę checkCurrentRole == true. W przeciwnym razie do tego czasu otrzymasz wyjątek bezpieczeństwa. Dlatego poprawna logika IsInRole .
Pomyślałem, że dodam inne rozwiązanie; ponieważ IsInRole
nie zawsze działa.
W zależności od potrzeb, jeśli potrzebujesz obsługi starszych systemów; lub nie masz pewności, jak klient fizycznie zarządza Twoim systemem. To rozwiązanie, które wdrożyłem; dla elastyczności i zmian.
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.
Więc powyższy kod ma kilka konstrukcji; faktycznie przetestuje, czy użytkownik korzysta z systemu Vista lub nowszego. W ten sposób, jeśli klient korzysta z XP bez frameworka lub frameworka beta sprzed lat, pozwoli ci to zmienić to, co chciałbyś zrobić.
Następnie przeprowadzi fizyczny test, aby uniknąć wartości zerowej dla konta.
Na koniec zapewni sprawdzenie, czy użytkownik rzeczywiście pełni odpowiednią rolę.
Wiem, że odpowiedź na to pytanie; ale pomyślałem, że moje rozwiązanie byłoby świetnym dodatkiem do strony dla każdego, kto przeszukuje stos. Moje rozumowanie za Protected Constructor pozwoliłoby ci użyć tej klasy jako klasy pochodnej, którą możesz kontrolować stan, kiedy klasa jest tworzona.
W ten sposób skończyłem ... Wymuszam działanie mojej aplikacji w trybie administratora. Aby to zrobić
1- Dodaj <ApplicationManifest>app.manifest</ApplicationManifest>
do csproj
pliku.
MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
</Project>
2- Dodaj poniższy app.manifest
plik do swojego projektu.
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>