如何在Windows上使用Go请求管理员权限

22
我希望我的应用程序无需每次右键单击并选择“以管理员身份运行”,就可以运行它。我希望 Windows 能像其他 Windows 应用程序一样提示我获取管理员权限。
考虑以下代码:
package main

import (
    "fmt"
    "io/ioutil"
    "time"
)

func main() {
    err := ioutil.WriteFile("C:/Windows/test.txt", []byte("TESTING!"), 0644)
    if err != nil {
        fmt.Println(err.Error())
        time.Sleep(time.Second * 3)
    }
}

如果您编译并双击它,它会打印:

打开:C:\Windows\test.txt:拒绝访问。

但是,如果您右键单击并以管理员身份运行,它将创建并写入该文件。

如何使它只需双击即可请求管理员权限?

2个回答

20

您需要嵌入一个清单文件,以告诉Windows您想要提升的权限。

该页面上的示例为:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
    version="9.0.0.0"
    processorArchitecture="x86"
    name="myapp.exe"
    type="win32"
/>
<description>My App</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
        <requestedPrivileges>
            <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
        </requestedPrivileges>
    </security>
</trustInfo>
</assembly>

这篇go-nuts帖子建议使用rsrc能够解决你的问题。

20

这是我用来检测自己是否以管理员身份运行并在需要时重新启动一个UAC提示的技术。这使我大多数情况下都可以作为标准用户运行,只有在需要时才提升权限。我在命令行工具中使用此方法,其中大多数功能不需要管理权限,但像-install或-uninstall这样的功能需要,因为它们要写入注册表或Program Files的HKLM。使用这种方法不需要清单。

package main

import (
    "fmt"
    "golang.org/x/sys/windows"
    "os"
    "syscall"
    "time"
)

func main() {
    // if not elevated, relaunch by shellexecute with runas verb set
    if !amAdmin() {
        runMeElevated()
    }
    time.Sleep(10*time.Second)

}

func runMeElevated() {
    verb := "runas"
    exe, _ := os.Executable()
    cwd, _ := os.Getwd()
    args := strings.Join(os.Args[1:], " ")

    verbPtr, _ := syscall.UTF16PtrFromString(verb)
    exePtr, _ := syscall.UTF16PtrFromString(exe)
    cwdPtr, _ := syscall.UTF16PtrFromString(cwd)
    argPtr, _ := syscall.UTF16PtrFromString(args)

    var showCmd int32 = 1 //SW_NORMAL

    err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd)
    if err != nil {
        fmt.Println(err)
    }
}

func amAdmin() bool {
    _, err := os.Open("\\\\.\\PHYSICALDRIVE0")
    if err != nil {
        fmt.Println("admin no")
        return false
    }
    fmt.Println("admin yes")
    return true
}

更多细节在此处可用:
https://gist.github.com/jerblack/d0eb182cc5a1c1d92d92a4c4fcc416c6


优秀的技术。将来可能会派上用场。 - Joppe
如果您是管理员,难道不需要关闭文件吗? - maja
"windows.GetCurrentProcessToken().IsElevated()" 是什么问题? - trueToastedCode

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