Golang中为什么macOS系统钥匙串提示不显示

Golang中为什么macOS系统钥匙串提示不显示 大家好,我是Go语言新手。

我正在尝试编写一个简单的Go程序,用于显示用户当前连接的WiFi网络密码。

当我通过终端手动输入以下命令时,系统会弹出要求输入用户凭据的提示框,填写后就会显示密码及其他一些信息:

security find-generic-password -D 'AirPort network password' -ga my_super_cool_ssid

但是当我在Go程序中执行这个命令时,钥匙串提示框没有显示,我只看到一些奇怪的信息输出:

keychain: "/Users/bb/Library/Keychains/login.keychain-db"
version: 512
class: "genp"
attributes: ... ...

以下是负责这部分功能的简单Go函数:

func getPassword(ssid string) {

  cmd := exec.Command("bash", "-c", "security find-generic-password", "-D", "'AirPort network password'", "-ga", ssid)

  cmd.Stdin = os.Stdin

  out, err := cmd.Output()

  if err != nil {

    log.Fatalf("cmd.Run() failed with %s\n", err)

  }

  fmt.Println(string(out))

}

先谢谢大家了。


更多关于Golang中为什么macOS系统钥匙串提示不显示的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

非常感谢,这解决了问题 🙂

干杯。

更多关于Golang中为什么macOS系统钥匙串提示不显示的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


由于某些原因,密码会输出到标准错误流,因此您可以使用 out, err := cmd.CombinedOutput() 来获取它。

out, err := cmd.CombinedOutput()

感谢您的帮助 🙂

现在几乎可以正常工作了 - 钥匙串提示已显示,但在我输入凭据后,终端中没有打印出WiFi网络密码。

然而,如果我手动在终端中运行此命令,除了WiFi密码如预期那样显示出来之外,其他情况完全相同。

您知道这是为什么吗?

你好

你在 exec.Command 中有一个错误,“security find-generic-password” 应该是两个参数而不是一个,而且你不需要为 AirPort 网络密码添加引号,否则引号会被传递给程序。你也可以直接调用 security 而不使用 bash。像这样:

cmd := exec.Command("/usr/bin/security", "find-generic-password", "-D", "AirPort network password", "-ga", ssid)

希望这对你有所帮助 🙂

在Go程序中执行security命令时,钥匙串提示框不显示是因为exec.Command默认不会分配终端(tty),而钥匙串的认证提示需要交互式终端才能显示。

问题主要出现在以下几个方面:

  1. 命令参数传递不正确 - 使用bash -c时应该将整个命令作为单个字符串传递
  2. 缺少终端分配 - 需要为子进程分配伪终端
  3. 标准输入处理 - 需要正确处理用户输入

以下是修正后的代码:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "log"
    "syscall"
    "unsafe"
)

func getPassword(ssid string) {
    // 正确的命令构造方式
    cmd := exec.Command("security", "find-generic-password", 
        "-D", "AirPort network password", 
        "-ga", ssid)
    
    // 设置标准输入输出
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    
    // 运行命令
    err := cmd.Run()
    if err != nil {
        log.Fatalf("cmd.Run() failed with %s\n", err)
    }
}

如果你需要更可靠地处理终端交互,可以使用os/exec结合伪终端:

import (
    "github.com/kr/pty"
    "os/exec"
)

func getPasswordWithPTY(ssid string) {
    cmd := exec.Command("security", "find-generic-password", 
        "-D", "AirPort network password", 
        "-ga", ssid)
    
    // 创建伪终端
    ptmx, err := pty.Start(cmd)
    if err != nil {
        log.Fatal(err)
    }
    defer ptmx.Close()
    
    // 将伪终端的输入输出连接到标准输入输出
    go func() {
        io.Copy(ptmx, os.Stdin)
    }()
    io.Copy(os.Stdout, ptmx)
}

或者使用更简单的方法,通过expect风格的交互:

func getPasswordInteractive(ssid string) {
    cmd := exec.Command("security", "find-generic-password", 
        "-D", "AirPort network password", 
        "-ga", ssid)
    
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    
    // 启动命令但不等待完成
    err := cmd.Start()
    if err != nil {
        log.Fatal(err)
    }
    
    // 等待命令完成
    err = cmd.Wait()
    if err != nil {
        log.Fatal(err)
    }
}

主要修改点:

  • 移除了不必要的bash -c包装
  • 正确设置了标准输入输出
  • 使用cmd.Run()而不是cmd.Output()来保持交互性

这样修改后,钥匙串的认证提示应该能够正常显示并等待用户输入。

回到顶部