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

URL: https://skillaria.top/zh/guides/git/git-token-auth-guide

自 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_` 开头。令牌只在创建后显示一次，请立即复制到密码管理器中保存。

### 步骤

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:@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:@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 并使用远程仓库。

## FAQ

**创建后还能再次查看 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 文件。


---
Source: Skillaria.Top (https://skillaria.top)
