Jak podnosić uprawnienia tylko wtedy, gdy jest to wymagane?

85

To pytanie dotyczy systemu Windows Vista!

Mam aplikację, która normalnie działa bez uprawnień administratora. Jest jedna czynność, która wymaga uprawnień administratora, ale nie chcę uruchamiać samej aplikacji z wyższymi uprawnieniami, kiedy wiem, że przez większość czasu użytkownik nawet nie będzie używał tej funkcji.

Myślę o pewnej metodzie, dzięki której mogę podnieść uprawnienia aplikacji na jakimś zdarzeniu (np. Naciśnięcie przycisku). Przykład:

Jeśli użytkownik kliknie ten przycisk, pojawi się okno dialogowe UAC lub zgoda. Jak mogę to zrobić?

Hemant
źródło

Odpowiedzi:

58

Nie sądzę, aby można było podnieść poziom aktualnie działającego procesu. Jak rozumiem, jest wbudowane w Windows Vista, że ​​uprawnienia administratora są nadawane procesowi podczas uruchamiania. Jeśli spojrzysz na różne programy, które wykorzystują UAC, powinieneś zobaczyć, że faktycznie uruchamiają one oddzielny proces za każdym razem, gdy trzeba wykonać czynność administracyjną (Menedżer zadań to jeden, Paint.NET to drugi, a drugi to w rzeczywistości aplikacja .NET ).

Typowym rozwiązaniem tego problemu jest określenie argumentów wiersza poleceń podczas uruchamiania procesu z podwyższonym poziomem uprawnień (sugestia abatishcheva jest jednym ze sposobów na zrobienie tego), tak aby uruchomiony proces wiedział tylko o wyświetleniu określonego okna dialogowego, a następnie kończy się po wykonaniu tej czynności zakończony. W związku z tym użytkownik powinien prawie nie zauważyć, że nowy proces został uruchomiony, a następnie zamknięty, i powinien raczej wyglądać tak, jakby zostało otwarte nowe okno dialogowe w tej samej aplikacji (zwłaszcza jeśli ktoś włamał się do głównego okna proces podwyższony jest dzieckiem procesu nadrzędnego). Jeśli nie potrzebujesz interfejsu użytkownika do podwyższonego dostępu, jeszcze lepiej.

Aby uzyskać pełne omówienie UAC w systemie Vista, polecam zapoznać się z tym artykułem na ten temat (przykłady kodu są w C ++, ale podejrzewam, że będziesz musiał użyć WinAPI i P / Invoke, aby zrobić większość rzeczy w C # tak czy inaczej). Mam nadzieję, że teraz przynajmniej widzisz właściwe podejście, chociaż zaprojektowanie programu zgodnego z UAC nie jest trywialne ...

Noldorin
źródło
4
Czy nastąpiła jakaś zmiana w systemie Windows 7 lub czy odpowiedź „nie, użyj nowego procesu” utrzymuje się? Dzięki ...
Radim Vansa
2
Brak zmian w systemie Windows 7 Niestety, przepraszam. (O ile wiem i jestem zwykłym użytkownikiem / programistą na Win7.)
Noldorin,
2
Dokładnie tak robi to menedżer zadań. Po kliknięciu przycisku, aby wyświetlić zadania dla wszystkich użytkowników, obecny menedżer zadań wywołuje następnie innego menedżera zadań z uprawnieniami administratora.
Natalie Adams
3
@NathanAdams Technicznie rzecz biorąc, najpierw otwiera nowego menedżera zadań. W przeciwnym razie, co robi otwarcie? :-)
wizzwizz4 20.04.2016
16

Jak tam powiedziano :

Process.StartInfo.UseShellExecute = true;
Process.StartInfo.Verb = "runas";

uruchomi proces jako administrator, aby zrobić wszystko, czego potrzebujesz z rejestrem, ale powróci do aplikacji z normalnymi uprawnieniami.

abatishchev
źródło
Obejmuje to nowy proces. dobrze? Szukałem podniesienia przywilejów samego obecnego procesu.
Hemant
Spróbuj użyć do Process.GetCurrentProcess ()
abatishchev
27
Nie możesz podwyższyć poziomu aktualnie uruchomionego procesu.
Jacob Proffitt
1
To nie jest prawda. Możesz zmienić właściciela procesu i ustawić wartości DACL i ACL dla użytkownika, nadając mu uprawnienia administracyjne ....
Nightforce2
4
@ nightforce2: z pewnością zadziała to tylko wtedy, gdy masz już uprawnienia administracyjne (tj. masz już wyższy poziom). W przeciwnym razie AdjustTokenPrivileges itp. Po prostu się nie powiedzie, nie?
Ben Schwehn
13

W następującym artykule bazy wiedzy MSDN 981778 opisano, jak „samodzielnie podwyższyć poziom uprawnień” aplikacji:

http://support.microsoft.com/kb/981778

Zawiera próbki do pobrania w językach Visual C ++, Visual C #, Visual Basic.NET.

Takie podejście pozwala uniknąć konieczności uruchamiania oddzielnego procesu, ale w rzeczywistości jest to oryginalna aplikacja, która jest ponownie uruchamiana, działając jako użytkownik z uprawnieniami. Niemniej jednak może to być bardzo przydatne w niektórych kontekstach, w których nie jest praktyczne kopiowanie kodu w osobnym pliku wykonywalnym.

Aby usunąć elewację, musisz zamknąć aplikację.

FruitBreak
źródło
1
Przydatny jako przycisk, ale jeśli chcesz tego samego dla elementu menu, czeka Cię jeden naprawdę zawiły bałagan.
Nyerguds
Link do odpowiedzi jest martwy, a link do komentarza wskazuje na długą listę 2608 pozycji.
DonBoitnott
Możesz go znaleźć tutaj
mirh
2

Może komuś przyda się ten prosty przykład:

using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Security.Principal;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    internal static class Program
    {
        private class Form1 : Form
        {
            internal Form1()
            {
                var button = new Button{ Dock = DockStyle.Fill };
                button.Click += (sender, args) => RunAsAdmin();
                Controls.Add(button);

                ElevatedAction();
            }
        }

        [STAThread]
        internal static void Main(string[] arguments)
        {
            if (arguments?.Contains("/run_elevated_action") == true)
            {
                ElevatedAction();
                return;
            }

            Application.Run(new Form1());
        }

        private static void RunAsAdmin()
        {
            var path = Assembly.GetExecutingAssembly().Location;
            using (var process = Process.Start(new ProcessStartInfo(path, "/run_elevated_action")
            {
                Verb = "runas"
            }))
            {
                process?.WaitForExit();
            }
        }

        private static void ElevatedAction()
        {
            MessageBox.Show($@"IsElevated: {IsElevated()}");
        }

        private static bool IsElevated()
        {
            using (var identity = WindowsIdentity.GetCurrent())
            {
                var principal = new WindowsPrincipal(identity);

                return principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
        }

    }
}
Konstantin S.
źródło
1

Wiem, że to stary post, ale jest to odpowiedź na każdą inną sugestię MarcP. Post msdn, do którego się odwołał, faktycznie restartuje aplikacje we wszystkich przykładach kodu. Przykłady kodu używają runasczasownika zaproponowanego już w innych sugestiach.

Pobrałem kod, aby się upewnić, ale jest to z oryginalnego artykułu MSDN:

4. Kliknij przycisk Tak, aby zatwierdzić elewację. Następnie oryginalna aplikacja zostanie ponownie uruchomiona, działając jako administrator z podwyższonym poziomem uprawnień.
5. Zamknij aplikację.

SpaceGhost440
źródło
1
Czy możesz dodać odnośne łącze MSDN? Nie mogę znaleźć użytkownika o nazwie MarcP.
Alf