UAC实现的最佳实践是什么?(.NET)

13

我正在考虑开发一个应用程序,大部分时间应该作为标准用户运行,但对于某些操作,需要提升管理员访问权限。用户体验应该像在Windows资源管理器中将东西复制到受保护文件夹中的方式。

现在问题是,在.NET中应如何实现?我知道只有整个进程或可能一些COM实例可以提升,而不是单个函数。但这正是我所需要的。我应该怎么做?编写两个可执行文件,一个带有清单,另一个没有;以编程方式再次提升相同的进程;使用某些COM内容?然后我就有了额外的特权,但如何告诉其他进程该怎么做呢?使用.NET远程(已弃用/复杂);使用套接字/管道/其他实现自己的IPC内容?这个提升的任务可能需要在处理过程中向用户询问某些事情。而且必须可以取消。

有很多东西告诉我UAC在内部如何工作,或者系统管理员如何配置它,但我没有找到任何回答这些基本问题的内容。

1个回答

3

看起来我们有两个不同的问题:

  1. 我应该如何处理需要提升权限的操作?
  2. 如果我使用单独的进程,我应该如何告诉另一个进程要做什么?

这是我回答它们的尝试:

  1. 从这个SO问题Windows 7 and Vista UAC - Programmatically requesting elevation in C#来看,似乎像你在问题中建议的一样(运行另一个进程并在启动时请求提升),是“正确的答案”。
  2. 至于告诉另一个进程要做什么,这是我会尝试的方法:

我将从将需要提升权限的每个操作拆分为自己的“helper”程序开始。这些辅助程序将仅执行单个操作,并通过命令行接收参数。

例如,假设您的程序需要停止/启动服务,我会编写一个名为servicecontroller的小助手程序(实际上,您可能希望使用net命令),该程序接受类似于以下命令行参数:
servicecontroller stop MyCoolService
servicecontroller start MyCoolService

这些参数将由“Main”程序构建,并在点击“OK”后传递。
但是,上述解决方案存在几个问题,您可能会或不会关心:
  1. 您正在通过命令行传递参数,这很容易被嗅探到
  2. 您受到ProcessStartInfo.Argument +程序路径的长度限制(来自MSDN:添加到进程的参数的长度加上完整路径的长度必须小于2080。
  3. 如果您需要此功能,则获取传递回来的信息可能有点棘手
通过更多的搜索,我发现了'DevZest'的博客文章,基本上推荐了我上面描述的内容。祝你好运!

根据评论中提出的额外问题进行编辑:

  1. 需要执行提升权限的操作时,您会建议启动单独的可执行文件还是同一可执行文件?
  2. (我在这个问题上读了行间)我应该多久提示用户执行这些操作?

不知道您具体做什么,以下是我的想法:

  1. 个人建议为每个操作创建单独的可执行文件,但不知道您要做什么,很难做出决定。总的来说,似乎您需要为每个提升权限的操作创建一个单独的进程。
  2. 我对您的第二个示例有点困惑,再次强调,不知道您要做什么,我只能根据您在评论中给出的示例进行回答。

在文件管理器示例中,我将执行以下操作:首先遍历每个目标目录,确定是否需要提升权限才能复制到任何目标位置。如果需要,我会标记一个指示需要以管理员身份执行操作的标志,然后提示用户,并将整个操作作为管理员执行。

关于文本编辑器示例,我会做类似于上面的事情。当用户提供目标目录时,请检查您是否具有对该位置的写访问权限,如果没有,请通知用户他们正在保存到需要提升权限的位置,并将他们的工作保存到可写位置(您程序的APPDATA或甚至是TEMP可能是一个不错的地方),然后启动复制过程请求提升权限。如果用户取消UAC对话框,请确保捕获此取消并删除临时文件。
我建议您不要保留提升权限的工作进程。如果您发现您的程序在其生命周期内需要多次请求提升权限(读作:1或2个边角情况),那么我会质疑为什么它没有标记为始终提升权限。我喜欢遵循“最少惊讶原则”,当我给您提升权限时,我希望您只执行请求它的操作,而不是通过第一个请求继续传递需要提升权限的操作。
所有这些都没有阻止你做上述操作,一旦你让某个进程获得了提升的权限,他就可以邀请他的所有伙伴。基于你想要保持一个提升的进程,为什么不保存程序的当前状态,并使用提升的特权重新启动程序并还原状态呢?在我看来,这与使工作进程始终处于提升状态是相同的。
如果您能告诉我们更多关于您要做什么的详细信息,我们可能能够找到更好的方法来完成这项任务,而不必遇到UAC问题。虽然有一些非常好的理由写入受UAC保护的区域,但在大多数情况下,程序不需要写入/访问这些位置。

1
为了在进程之间传递参数,您可以使用环境变量和控制台输出。如果您创建一个进程启动信息,您可以为该进程设置专用的环境变量,并在启动后读取标准输出。 - Zebi
嗯,我猜更多的问题会随着答案而来... 首先:您会推荐启动单独的可执行文件还是使用不同的参数启动相同的可执行文件?我需要部署1个还是2个 .exe 文件?其次:我可能需要与提升的进程进行大量交互。仅通过简单的命令行参数告诉它该做什么可能不够。我需要状态或数据返回值。想象一下文件管理器/文本编辑器:我正在复制文件,然后突然确定我需要更高的权限。另一个进程需要无缝地继续复制工作。或者一个文本编辑器... - ygoe
<-需要将文件保存到受保护的位置。必须传递要写入的文件数据,该数据可能是几兆字节或更多。我希望将该进程保留一段时间,以便可以告诉它其他事情,而不会反复干扰用户的每个操作。此外,所有这些操作可能需要提升权限,这取决于它们所操作的内容。我想我会将这些功能外包到一个公共DLL中,并从两个可执行文件中使用它。 - ygoe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接