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 #?
c#
windows-administration
Fliskov
źródło
źródło
return new WindowsPrincipal(WindowsIdentity.GetCurrent()) .IsInRole(WindowsBuiltInRole.Administrator);
źródło
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.
źródło
Powyższe odpowiedzi z IsInRole są w rzeczywistości poprawne: sprawdza, czy bieżący użytkownik ma uprawnienia administratora. Jednak,
(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 .
źródło
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.
źródło
Jeśli Twoja aplikacja musi być uruchamiana z uprawnieniami administratora, dobrze byłoby zaktualizować jej manifest.
Ustaw
requestedExecutionlevel
narequireAdminstrator
.źródło
W ten sposób skończyłem ... Wymuszam działanie mojej aplikacji w trybie administratora. Aby to zrobić
1- Dodaj
<ApplicationManifest>app.manifest</ApplicationManifest>
docsproj
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>
źródło