教程

GitHub Token 与 Git 认证:个人访问令牌、Git Credential Manager 与免密推送

更新于: · Skillaria.Top

自 2021 年 8 月起,GitHub 不再接受账号密码进行 HTTPS 方式的 Git 操作,取而代之的是个人访问令牌(token)或通过 Git Credential Manager 在浏览器中登录。令牌在 github.com 的 Settings → Developer settings 中创建,在 git push 或 git clone 时输入以代替密码,并由 credential.helper 保存。

为什么 Git 不再接受 GitHub 密码

如果你在执行 git push 时输入 github.com 的用户名和密码却被拒绝,问题不在于输错了字符。自 2021 年 8 月 13 日起,GitHub 已停用通过 HTTPS 进行 Git 操作时的密码登录。现在需要使用个人访问令牌(personal access token,PAT),或者使用由 Git Credential Manager 完成的浏览器授权。

出现的错误信息大致如下:

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/... for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/user/project.git/'

原因很简单:账号密码拥有对全部内容的完整访问权限,无法限制到某一个仓库,而且撤销起来很麻烦。令牌则是为某个任务单独创建的,有有效期和权限范围,一旦泄露,只需几分钟删除令牌,无需修改密码。GitLab 和 Bitbucket 也走了同样的路线,因此下面的内容在原理上同样适用于它们。

两种认证方式:HTTPS 与 SSH

Git 通过两种协议之一与远程仓库通信,认证方式取决于所用的协议。

协议仓库地址认证方式
HTTPShttps://github.com/user/project.git令牌,或 Git Credential Manager(浏览器登录)
SSHgit@github.com:user/project.git一对 SSH 密钥:私钥在你的电脑上,公钥添加在 GitHub 设置中

SSH 密钥只需配置一次,之后 Git 不再询问用户名或密码。SSH 密钥的生成与添加,已在 Git 设置的相关文章中详细介绍,这里我们专注于 HTTPS,因为新手最常在这里遇到密码提示。要查看仓库使用的协议,可以执行:

git remote -v
origin  https://github.com/user/project.git (fetch)
origin  https://github.com/user/project.git (push)

如何创建 GitHub 令牌(personal access token)

Personal access token 是一个很长的随机字符串,GitHub 用它代替密码,供程序访问。Classic 令牌以 ghp_ 开头,fine-grained 令牌以 github_pat_ 开头。令牌只在创建后显示一次,请立即复制到密码管理器中保存。

步骤

  1. 登录 github.com,点击右上角的头像,打开 Settings。
  2. 在左侧菜单底部选择 Developer settings,然后选择 Personal access tokens。
  3. 选择类型:Fine-grained tokens(推荐)或 Tokens (classic),然后点击创建新令牌。
  4. 设置一个容易识别的名称(例如「笔记本,工作用」)、有效期和权限。
  5. 点击生成按钮,并立即复制令牌。

Fine-grained 还是 classic

Fine-grained 令牌只能访问指定的仓库,并且权限可以精细设置。日常的代码工作,选择需要的仓库,并在仓库权限中授予 Contents: Read and write,这足以完成 clone、pull 和 push。如果只是读取私有仓库,设置为只读即可。

Classic 令牌对你的所有仓库都有效。要向仓库推送,需要 repo 范围;若要修改 .github/workflows 中的文件,还需要 workflow 范围。Classic 更简单,但也更危险:一旦泄露,整个账号都会暴露。

有效期

GitHub 提供几种有效期选项,也可以自定义日期。可以创建没有有效期的令牌,但不建议这样做:被遗忘的永久令牌是常见的安全漏洞。合理的做法是设置 30 到 90 天,并在 GitHub 于到期前发到邮箱的提醒后重新生成。

使用令牌执行 git push 与 git clone

使用令牌比想象中简单:Git 会提示输入「Password」,你把令牌粘贴进去即可,代替密码。

$ git push origin main
Username for 'https://github.com': your-login
Password for 'https://your-login@github.com': <粘贴令牌>

在终端中输入密码时不会显示任何字符,这是正常的:粘贴令牌后按回车即可。在 Windows 的 Git Bash 中,可以用 Shift+Insert 或鼠标右键粘贴。

使用令牌执行 git clone

私有仓库的克隆方式相同:git clone 会询问用户名和令牌。如果希望免去询问(例如在脚本中),可以把令牌直接写进地址:

git clone https://your-login:<TOKEN>@github.com/user/project.git

注意这样做的缺点:带有令牌的地址会保存在 .git/config 中,还可能进入 shell 的历史记录。克隆完成后,最好把令牌从地址中去掉:

git remote set-url origin https://github.com/user/project.git

在 CI 系统中,令牌应通过加密的环境变量传递,而不是写进文件。在 GitHub Actions 中,当前仓库已经内置了 GITHUB_TOKEN,通常不需要单独的 PAT。

GitLab:使用令牌执行 git clone

在 GitLab 中,令牌在个人资料设置的 Access tokens 部分创建;处理代码需要 read_repository 和 write_repository 范围。方法相同:GitLab 用户名作为用户名,令牌作为密码。

git clone https://oauth2:<TOKEN>@gitlab.com/group/project.git

GitLab 接受 oauth2 作为任何个人令牌的用户名,也可以使用你自己的登录名。

Git pull 与 fetch

对于公开仓库,git pull 和 git clone 无需认证即可使用。只有私有仓库或执行 git push 时才会询问用户名和令牌。如果在公开项目中 pull 时突然要求密码,多半是地址拼写有误:GitHub 对不存在的仓库和被关闭的私有仓库给出的响应是相同的。

Git Credential Manager 是什么

每次 push 都输入令牌很麻烦。这项工作由 credential helper 承担,它是 Git 需要凭据时调用的辅助程序。Git 把服务器地址交给它,它再从自己的存储中返回用户名和密码(或令牌)。

Git Credential Manager(GCM)是其中最方便的一种。它是 GitHub 与 Microsoft 共同开发的跨平台程序:第一次 push 时会打开登录窗口或浏览器,你在 GitHub 上完成授权(包括双因素认证),GCM 会自动获取令牌,并将其保存到系统的安全存储中。这种情况下无需手动创建 PAT。

GCM 支持 GitHub、GitLab、Bitbucket 和 Azure DevOps。在 Git for Windows 中它默认安装,就是安装程序中选择 credential helper 时的那个选项。

常见的 credential.helper 取值

取值存储位置适用场景
managerGit Credential Manager:Windows 凭据管理器、macOS 钥匙串、Linux 的 Secret Service推荐用于工作电脑
osxkeychainmacOS 钥匙串Mac 上 Git 的标准 helper
cache内存中,默认 15 分钟不想把令牌存到磁盘的 Linux 服务器
store以明文保存在 ~/.git-credentials 中仅用于隔离的机器;任何能读取该文件的人都能拿到令牌

在 Windows、macOS 和 Linux 上配置 Git 认证

查看当前已配置的 helper:

git config --show-origin --get-all credential.helper

Windows

如果安装 Git 时保留了默认设置,GCM 已经可以使用:第一次在 Git Bash、PowerShell 或 VS Code 中 push 时,会弹出 GitHub 登录窗口。如果 helper 没有配置,可以手动启用:

git config --global credential.helper manager

macOS

Mac 上的 Git 通常已经使用 osxkeychain:输入过一次的令牌会保存到钥匙串中。如果想使用浏览器登录,请安装 Git Credential Manager(例如通过 Homebrew:brew install --cask git-credential-manager),它会自动把自己写进配置。

Linux

在 Linux 上,GCM 需要单独安装(.deb 包,或从项目的发布页下载压缩包),然后进行配置并选择存储方式:

git-credential-manager configure
git config --global credential.credentialStore secretservice

在没有图形界面的服务器上,更简单的做法是临时缓存:

git config --global credential.helper 'cache --timeout=3600'

另一种 GitHub 方式:gh auth login

如果安装了 GitHub CLI,执行 gh auth login 会引导你在浏览器中登录,而 gh auth setup-git 会让 Git 从 gh 获取凭据。这是「在 Git Bash 中登录」的一种便捷方式,只需一条命令。

如何清除或更新已保存的 Git 密码

最常见的情况是:令牌过期了,或者你换了账号,但 Git 仍然使用旧的数据,结果出现 Authentication failed。这时需要删除已保存的记录,下一次 push 时 Git 就会重新询问。

通用命令

适用于任何 helper:

printf "protocol=https\nhost=github.com\n\n" | git credential reject

在 Windows 上重置 Git 凭据

打开「控制面板」→「凭据管理器」→「Windows 凭据」,找到形如 git:https://github.com 的记录并删除。也可以在命令行中完成:

cmdkey /list | findstr git
cmdkey /delete:git:https://github.com

如果使用的是 GCM,它也有自己的退出登录命令:git credential-manager github logout <用户名>。

macOS

打开「钥匙串访问」,找到类型为「互联网密码」的 github.com 记录并删除。也可以在终端中执行:

git credential-osxkeychain erase
host=github.com
protocol=https

输入最后一行后,再按一次回车,发送一个空行。

Linux 与 store

对于 store,从 ~/.git-credentials 中删除包含 github.com 的那一行;对于 cache,执行 git credential-cache exit。

认证错误及其解决方法

Support for password authentication was removed

你输入了账号密码。请创建令牌并粘贴到 Password 输入框中,或配置 Git Credential Manager。如果错误反复出现,而且没有要求输入密码,说明旧密码仍保存在存储中,请按上文方法删除。

git push: Authentication failed

按出现频率从高到低,原因包括:令牌已过期;令牌已被撤销;fine-grained 令牌没有访问该仓库的权限,或 Contents 只授予了读取权限;存储中保存的是另一个账号的数据。请在 Developer settings 中检查令牌的有效期和权限,并清除保存的凭据。

remote: Permission denied (403)

认证已通过,但你的账号没有该仓库的写入权限。仓库所有者需要把你添加为 Collaborators,或者你可以通过自己的 fork 和 pull request 工作。

Repository not found

对于私有仓库,GitHub 不会透露它是否存在,因此令牌错误时也会显示「not found」。请用 git remote -v 检查地址,并确认令牌的权限。

Git clone 每次都要求输入密码

说明没有配置 credential helper。启用 manager 或 osxkeychain,在第一次成功输入后,Git 就不会再询问。另一种办法是改用 SSH。

如何安全地保存令牌

  • 授予最少的权限:使用只针对所需仓库的 fine-grained 令牌,而不是带 repo 范围的 classic 令牌。
  • 设置有效期,到期后重新生成令牌,而不是无限期地延长。
  • 不要提交令牌,也不要把它写进 remote 地址;如果令牌进入了公开仓库,GitHub 可能会自动撤销它,但你仍应视其为已泄露并亲自删除。
  • 使用系统存储(GCM、钥匙串),而不是 store。
  • 一个令牌对应一台电脑或一个任务:这样泄露时,你只需撤销这一个令牌。

总结

自 2021 年起,GitHub 账号密码已不能用于 HTTPS 方式的 Git 操作。有三种可行的方法:在浏览器中通过 Git Credential Manager 登录、创建 GitHub 令牌代替密码输入,或者改用 SSH 密钥。令牌在 Settings → Developer settings 中创建,由 credential.helper 保存。遇到 Authentication failed 时,通常重新生成令牌并清除旧的凭据就能解决。在本课程的 Git 实践中,我们也会详细讲解如何连接 GitHub 并使用远程仓库。

常见问题

创建后还能再次查看 GitHub 令牌吗?

不能,GitHub 只显示一次令牌。如果没有保存,请删除旧令牌并重新创建。

克隆公开仓库需要令牌吗?

不需要。公开仓库无需认证即可通过 git clone 克隆,并通过 git pull 更新;只有私有仓库和 git push 才需要令牌。

令牌过期后会怎样?

Git 会开始报 Authentication failed。请创建新令牌(或对旧令牌点击 Regenerate),删除已保存的凭据,并在下一次 push 时输入新令牌。

GitHub 令牌能用于开启双因素认证的账号吗?

可以,开启 2FA 时正需要令牌:它代替密码和验证码完成 Git 操作。通过浏览器登录时,Git Credential Manager 会自行完成 2FA。

Git 把登录名和密码保存在哪里?

Git 本身不保存,而是由 credential helper 保存:Windows 凭据管理器、macOS 钥匙串、Linux 的 Secret Service,或使用 helper store 时的 ~/.git-credentials 文件。

通过视频学习本主题

课程“Git 从零基础到胜任开发者”结合实践详细讲解了这一主题。

前往课程