Как повышать привилегии только при необходимости?

85

Этот вопрос относится к Windows Vista!

У меня есть приложение, которое обычно работает без прав администратора. Есть одно действие, которое требует административных привилегий, но я не хочу запускать само приложение с более высокими привилегиями, если я знаю, что большую часть времени пользователь даже не будет использовать эту функцию.

Я думаю об определенном методе, с помощью которого я могу повысить привилегии приложения в отношении какого-либо события (например, нажатия кнопки). Пример:

Если пользователь нажимает эту кнопку, ему предлагается диалоговое окно UAC или согласие. Как я могу это сделать?

Hemant
источник

Ответы:

58

Я не верю, что можно улучшить текущий процесс. Насколько я понимаю, в Windows Vista встроены права администратора, которые предоставляются процессу при запуске. Если вы посмотрите на различные программы, использующие UAC, вы увидите, что они фактически запускают отдельный процесс каждый раз, когда необходимо выполнить административное действие (диспетчер задач - это одно, Paint.NET - другое, последнее фактически является приложением .NET. ).

Типичным решением этой проблемы является указание аргументов командной строки при запуске процесса с повышенными правами (предложение Абатищева - один из способов сделать это), чтобы запущенный процесс знал только, чтобы отобразить определенное диалоговое окно, а затем выйти после того, как это действие было выполнено. завершено. Таким образом, пользователю вряд ли должно быть заметно, что новый процесс был запущен, а затем завершен, и скорее будет выглядеть так, как если бы было открыто новое диалоговое окно в том же приложении (особенно если вы взломали, чтобы сделать главное окно повышенный процесс, дочерний по отношению к родительскому процессу). Если вам не нужен пользовательский интерфейс для повышенного доступа, даже лучше.

Для полного обсуждения UAC в Vista я рекомендую вам просмотреть эту статью по этому вопросу (примеры кода приведены на C ++, но я подозреваю, что вам нужно будет использовать WinAPI и P / Invoke, чтобы делать большинство вещей на C #. так или иначе). Надеюсь, теперь вы, по крайней мере, видите правильный подход, хотя разработка программы, совместимой с UAC, далеко не тривиальная задача ...

Нолдорин
источник
4
Есть ли какие-либо изменения в Windows 7 или остается ответ «нет, использовать новый процесс»? Спасибо ...
Radim Vansa
2
Боюсь, что никаких изменений в Windows 7 нет. (Насколько я знаю, и я являюсь постоянным пользователем / разработчиком Win7.)
Нолдорин
2
Именно так это делает диспетчер задач. Когда вы нажимаете кнопку, чтобы отобразить задачи для всех пользователей, существующий текущий диспетчер задач вызывает другой диспетчер задач с правами администратора.
Натали Адамс
3
@NathanAdams Технически он первым открывает новый диспетчер задач. Иначе что делает открытие? :-)
wizzwizz4
16

Как уже было сказано там :

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

запустит процесс от имени администратора, чтобы делать с реестром все, что вам нужно, но вернется в приложение с обычными привилегиями.

Абатищев
источник
Это предполагает охват нового процесса. правильно? Я искал повышения привилегий самого текущего процесса.
Hemant
Попробуйте использовать для Process.GetCurrentProcess ()
абатищев
27
Вы не можете повысить уровень запущенного в данный момент процесса.
Джейкоб Проффитт,
1
Это неправда. Вы можете изменить владельца процесса и установить значения DACL и ACL для пользователя, наделив его административными полномочиями ....
Nightforce2,
4
@ nightforce2: конечно, это сработает только в том случае, если у вас уже есть права администратора (т.е. у вас уже есть повышенные права). В противном случае AdjustTokenPrivileges и т. Д. Просто выйдет из строя, не так ли?
Бен Швен,
13

Следующая статья базы знаний MSDN 981778 описывает, как «самостоятельно поднять» приложение:

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

Он содержит загружаемые образцы на Visual C ++, Visual C #, Visual Basic.NET.

Этот подход позволяет избежать необходимости запускать отдельный процесс, но на самом деле перезапускается исходное приложение, работающее от имени пользователя с повышенными привилегиями. Тем не менее, это может быть очень полезно в некоторых контекстах, где нецелесообразно дублировать код в отдельном исполняемом файле.

Чтобы убрать возвышение, нужно выйти из приложения.

FruitBreak
источник
1
Удобно для кнопки, но когда вам нужно то же самое для пункта меню, вас ждет один действительно запутанный беспорядок.
Nyerguds
3
@Todd Вы можете найти код здесь: https://code.msdn.microsoft.com/windowsapps/CSUACSelfElevation-644673d3
Matthiee
Ссылка ответа не работает, а ссылка на комментарий указывает на длинный список из 2608 элементов.
DonBoitnott
Вы можете найти это здесь
mirh
2

Возможно, кому-то пригодится такой простой пример:

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);
            }
        }

    }
}
Константин С.
источник
1

Я знаю, что это старый пост, но это ответ всем, кто сталкивается с предложением MarcP. Сообщение msdn, на которое он ссылается, действительно перезапускает приложения во всех примерах кода. В примерах кода используется runasглагол, уже предложенный в других предложениях.

Я загрузил код, чтобы убедиться, но это из исходной статьи msdn:

4. Щелкните Да, чтобы утвердить отметку. Затем исходное приложение перезапускается под управлением администратора с повышенными правами.
5. Закройте приложение.

Космический Призрак440
источник
1
Можете ли вы добавить соответствующую ссылку MSDN? Я не могу найти пользователя по имени MarcP.
Альф