You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS SwiftUI应用如何通过系统认证执行需密码的脚本?

问题描述

我正在开发一款基于SwiftUI的macOS应用,需要执行需输入系统(或管理员)密码的脚本。之前用SecureField让用户输入密码触发脚本,但不符合苹果规范已移除。现在用LAContext做系统认证,但认证成功后无法获取用户密码,也没法从Keychain读取(还没存储过)。执行脚本时Xcode终端报错:

sudo: a password is required
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper

需要合规完成系统认证并执行需密码的脚本。


合规解决方案:使用Authorization Services框架(苹果官方推荐)

苹果禁止应用直接获取用户密码,正确的思路是通过Authorization Services框架获取权限凭证,而非拿到密码本身。这个框架是macOS处理权限认证的标准方案,完全符合Sandbox与隐私规范。

核心步骤

1. 创建授权引用

先通过AuthorizationCreate生成一个授权引用,作为后续权限请求的基础。

2. 请求用户认证

用AuthorizationCopyRights请求对应权限(比如执行脚本的kAuthorizationRightExecute),此时会触发系统原生的认证弹窗(支持Touch ID、密码验证,和LAContext体验一致)。

3. 凭授权执行脚本

拿到合法授权后,用AuthorizationExecuteWithPrivileges直接执行需要权限的脚本,无需手动处理密码。

完整示例代码

import Foundation
import Security

func runPrivilegedScript() {
    var authRef: AuthorizationRef?
    let createStatus = AuthorizationCreate(nil, nil, [], &authRef)
    
    guard createStatus == errAuthorizationSuccess, let auth = authRef else {
        print("授权引用创建失败:\(createStatus)")
        return
    }
    
    // 定义需要的权限:执行系统级命令/脚本
    let requiredRight = kAuthorizationRightExecute as String
    let rightsArray = [requiredRight] as [CFString]
    
    // 请求用户认证
    var authStatus = AuthorizationCopyRights(auth, rightsArray as CFArray, nil, [], nil)
    
    if authStatus == errAuthorizationSuccess {
        // 替换为你的脚本绝对路径和参数
        let scriptPath = "/path/to/your/script.sh"
        let scriptArgs = ["arg1", "arg2"]
        
        // 执行脚本
        var outputFileDescriptor: Int32 = 0
        authStatus = AuthorizationExecuteWithPrivileges(auth, scriptPath, [], scriptArgs as CFArray, &outputFileDescriptor)
        
        if authStatus == errAuthorizationSuccess {
            // 读取脚本输出
            let fileHandle = FileHandle(fileDescriptor: outputFileDescriptor)
            let outputData = fileHandle.readDataToEndOfFile()
            if let outputStr = String(data: outputData, encoding: .utf8) {
                print("脚本输出:\(outputStr)")
            }
            fileHandle.closeFile()
        } else {
            print("脚本执行失败:\(authStatus)")
        }
    } else {
        print("用户认证失败:\(authStatus)")
    }
    
    // 释放授权引用
    AuthorizationFree(auth, [])
}

关键说明

  • 全程无需获取用户密码,所有认证逻辑由系统接管,完全符合苹果规范
  • 系统弹窗支持生物识别、密码等方式,和LAContext的体验一致
  • 如果启用了App Sandbox,需根据脚本操作的资源配置对应的权限(比如文件读写权限)

内容的提问来源于stack exchange,提问作者Muhammad Danish Qureshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:07:40