如何仅在需要时提升权限?

Posted

技术标签:

【中文标题】如何仅在需要时提升权限?【英文标题】:How to elevate privileges only when required? 【发布时间】:2010-10-09 01:19:06 【问题描述】:

此问题适用于 Windows Vista!

我有一个应用程序,它通常在没有管理权限的情况下工作。有一项活动确实需要管理权限,但是当我知道大多数时候用户甚至不会使用该功能时,我不想以更高的权限启动应用程序本身。

我正在考虑某种方法,通过该方法我可以在某些事件(例如按下按钮)上提升应用程序的权限。示例:

如果用户单击此按钮,则会提示他使用 UAC 对话框或同意。我该怎么做?

【问题讨论】:

【参考方案1】:

我不相信提升当前正在运行的进程是可能的。据我了解,它内置于 Windows Vista 中,在启动时授予进程管理员权限。如果您查看使用 UAC 的各种程序,您应该看到它们实际上在每次需要执行管理操作时启动一个单独的进程(任务管理器是一个,Paint.NET 是另一个,后者实际上是一个 .NET 应用程序)。

此问题的典型解决方案是在启动提升的进程时指定命令行参数(abatishchev 的建议是这样做的一种方法),以便启动的进程只知道显示某个对话框,然后在此之后退出动作已经完成。因此,用户几乎不会注意到一个新进程已经启动然后退出,并且宁愿看起来好像同一个应用程序中的一个新对话框已经打开(特别是如果你有一些黑客来制作主窗口的主窗口)提升的进程是父进程的子进程)。如果您不需要用于提升访问权限的 UI,那就更好了。

关于 Vista 上的 UAC 的完整讨论,我建议您查看该主题的 this very through article(代码示例使用 C++,但我怀疑您需要使用 WinAPI 和 P/Invoke 来完成大部分操作无论如何在 C# 中)。希望您现在至少看到了正确的方法,尽管设计一个符合 UAC 的程序绝非易事......

【讨论】:

Windows 7 是否有任何变化,或者“否,使用新进程”的答案是否成立?谢谢... 恐怕Windows 7 没有变化,抱歉。 (据我所知,我是 Win7 的普通用户/开发人员。) 这正是任务管理器的工作方式。当您单击按钮以显示所有用户的任务时,当前任务管理器会调用另一个具有管理员权限的任务管理器。 @NathanAdams 从技术上讲,它首先打开新的任务管理器。否则,开场做什么? :-)【参考方案2】:

正如there所说:

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

将以管理员身份运行该进程以对注册表执行您需要的任何操作,但以正常权限返回您的应用程序。

【讨论】:

这涉及跨越一个新流程。正确的?我正在寻找提升当前进程本身的权限。 尝试使用Process.GetCurrentProcess() 您不能提升当前正在运行的进程。 这不是真的。您可以更改进程的所有者,并为用户设置 DACL 和 ACL 值,赋予他们管理权限.... @nightforce2:当然,这只有在您已经拥有管理权限(即您已经被提升)的情况下才有效。否则 AdjustTokenPrivileges 等就会失败,不是吗?【参考方案3】:

以下 MSDN 知识库文章 981778 描述了如何“自我提升”应用程序:

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

它包含可下载的 Visual C++、Visual C#、Visual Basic.NET 示例。

这种方法绕过了启动单独进程的需要,但实际上它是重新启动的原始应用程序,以提升的用户身份运行。尽管如此,在某些无法在单独的可执行文件中复制代码的情况下,这可能仍然非常有用。

要移除海拔高度,您需要退出应用程序。

【讨论】:

一个按钮很方便,但是当你想要一个菜单​​项也一样时,你会遇到一个非常复杂的混乱。 @Todd 你可以在这里找到代码:https://code.msdn.microsoft.com/windowsapps/CSUACSelfElevation-644673d3 答案的链接已失效,评论的链接指向一个 2608 项的长列表。 你可以找到它here【参考方案4】:

您需要一个 UAC 名字对象和代码以提升为 COM 对象运行。

See this question.

Documentation on MSDN.

【讨论】:

【参考方案5】:

也许有人会派上用场这个简单的例子:

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

    

【讨论】:

【参考方案6】:

我知道这是一篇旧帖子,但这是对遇到 MarcP 建议的任何其他人的回应。他引用的 msdn 帖子确实重新启动了所有代码示例中的应用程序。代码示例使用其他建议中已经提出的runas 动词。

我下载了代码以确保,但这是来自原始 msdn 文章:

4。单击“是”以批准高程。然后,原来的应用程序 重新启动,以提升的管理员身份运行。 5. 关闭应用程序。

【讨论】:

您可以添加有问题的 MSDN 链接吗?我找不到名为 MarcP 的用户。

以上是关于如何仅在需要时提升权限?的主要内容,如果未能解决你的问题,请参考以下文章

如何提升WINDOWS XP管理权限

linux怎么提升root权限啊?用su和sudo 也不行啊?

以提升的权限运行时如何正确检测网络驱动器

怎样提升Windows7的用户权限?

VC如何将自身进程提升至管理员权限

如何使用 ctypes 运行具有提升的 UAC 权限的脚本?