GitHub Token 与 Git 认证:个人访问令牌、Git Credential Manager 与免密推送
自 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 通过两种协议之一与远程仓库通信,认证方式取决于所用的协议。
| 协议 | 仓库地址 | 认证方式 |
|---|---|---|
| HTTPS | https://github.com/user/project.git | 令牌,或 Git Credential Manager(浏览器登录) |
| SSH | git@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_ 开头。令牌只在创建后显示一次,请立即复制到密码管理器中保存。
步骤
- 登录 github.com,点击右上角的头像,打开 Settings。
- 在左侧菜单底部选择 Developer settings,然后选择 Personal access tokens。
- 选择类型:Fine-grained tokens(推荐)或 Tokens (classic),然后点击创建新令牌。
- 设置一个容易识别的名称(例如「笔记本,工作用」)、有效期和权限。
- 点击生成按钮,并立即复制令牌。
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 取值
| 取值 | 存储位置 | 适用场景 |
|---|---|---|
manager | Git Credential Manager:Windows 凭据管理器、macOS 钥匙串、Linux 的 Secret Service | 推荐用于工作电脑 |
osxkeychain | macOS 钥匙串 | 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 文件。