使用SSH和令牌解决常见的Git身份验证错误

通过将远程URL与SSH密钥、HTTPS令牌和凭据助手匹配,修复常见的Git身份验证失败问题。

使用SSH和令牌解决常见的Git身份验证错误

大多数Git身份验证问题归根结底是远程URL、Git尝试使用的凭据以及Git托管账户权限之间的不匹配。错误文本可能看起来很严重,但一旦你知道Git走的是哪条路径,修复方法通常是机械性的。

从远程URL开始:

git remote -v

如果你看到 https://github.com/org/repo.git,Git正在使用HTTPS,并且需要用户名加令牌或能提供令牌的凭据助手。如果你看到 [email protected]:org/repo.git,Git正在使用SSH,并且需要与主机注册的公钥匹配的私钥。

在排查问题时不要混用两者。选择HTTPS或SSH,使远程URL匹配,然后直接测试该路径。

逐字阅读错误信息

fatal: Authentication failed for 'https://...' 通常意味着Git到达了服务器,但没有提供有效的HTTPS凭据。旧的凭据可能被缓存,令牌可能已过期,或者令牌可能没有访问该仓库的权限。

remote: Permission to org/repo denied403 Forbidden 通常意味着你的身份被识别,但没有执行该操作的权限。例如,你可能使用了错误账户的令牌、没有写权限的令牌,或者附加到不同用户的SSH密钥。

Permission denied (publickey) 意味着SSH没有提供服务器接受的密钥。

HTTPS下重复的用户名/密码提示通常意味着Git不断收到拒绝并再次询问。在需要令牌进行Git操作的主机上,反复输入账户密码没有帮助。

使用个人访问令牌修复HTTPS

对于HTTPS远程,在你的Git主机账户设置中创建一个个人访问令牌。GitHub、GitLab、Bitbucket和自托管平台的具体菜单名称不同,但形式相同:创建令牌,授予仓库访问权限,设置符合组织策略的过期时间,并立即复制。

当Git提示时,使用你的正常用户名并粘贴令牌作为密码:

Username: your-username
Password: <paste-token-here>

使用能工作的最小权限。对于你推送的私有仓库,你需要读写仓库访问权限。对于克隆公共仓库,你可能根本不需要令牌。细粒度令牌和组织SSO规则可能增加另一层:令牌可能存在,但仍需批准或SSO授权才能访问公司仓库。

如果Git从未提示输入新令牌,它可能正在使用旧的缓存凭据。清除该主机的存储条目,然后重试。

在macOS上,检查钥匙串访问中与你的Git主机相关的条目,例如 github.comgit:https://github.com

在Windows上,打开凭据管理器并删除该主机的相关通用凭据。

在Linux上,检查你配置的助手:

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

cache 助手将凭据临时存储在内存中。store 助手将凭据以明文形式写入磁盘,除非你配置了更安全的存储层,因此要谨慎使用。Git的凭据助手系统旨在向助手请求凭据并让助手保存成功的凭据;安全性取决于你选择的助手。

一个有用的HTTPS重置序列是:

git remote -v
git config --show-origin --get-all credential.helper
# 从操作系统凭据存储中移除旧凭据
git ls-remote origin

git ls-remote origin 是一个干净的测试,因为它联系远程而不改变你的工作树。

使用SSH密钥修复SSH

对于SSH远程,首先检查你是否已有密钥:

ls -al ~/.ssh

常见的密钥名称包括 id_ed25519id_rsa 和主机特定名称如 github_work_ed25519.pub 文件是你上传到Git主机的公钥。没有 .pub 的文件是私钥,不应共享。

如果你需要新密钥,Ed25519 是现代系统上的好默认选择:

ssh-keygen -t ed25519 -C "[email protected]"

除非你的环境有特定的自动化原因不使用,否则使用密码短语。然后将公钥添加到你的Git主机账户或部署密钥设置:

cat ~/.ssh/id_ed25519.pub

直接测试连接:

ssh -T [email protected]

对于GitLab或Bitbucket,替换主机名。成功的测试通常会打印一条问候语或消息,说明不提供shell访问。这没问题;Git-over-SSH身份验证仍然可以工作。

如果SSH仍然失败,询问SSH客户端它在做什么:

ssh -vT [email protected]

查找显示提供了哪些密钥的行。如果你的密钥未被提供,将其加载到代理中:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

对于同一主机上的多个账户,使用 ~/.ssh/config 以便Git知道哪个密钥属于哪个远程:

Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/github_work_ed25519
  IdentitiesOnly yes

然后将仓库指向该别名:

git remote set-url origin git@github-work:org/repo.git

这避免了SSH将你的个人密钥提供给工作仓库的常见问题。

干净地切换协议

如果你的团队标准化使用SSH,像这样更改HTTPS远程:

git remote set-url origin [email protected]:ORG/REPO.git

如果你的公司阻止SSH或需要HTTPS检查,则反过来切换:

git remote set-url origin https://github.com/ORG/REPO.git

更改URL后,用读取操作测试:

git fetch origin

然后测试失败的操作:

git push origin HEAD

如果fetch成功但push失败,则身份验证可能有效,授权是问题。检查分支保护、仓库角色、令牌范围和组织SSO规则。

CI和服务器环境

在构建代理和服务器上,尽可能避免使用个人的令牌。优先使用部署密钥、机器用户或CI系统的内置凭据存储。将秘密排除在命令历史和日志之外。除非你在受控的临时环境中,否则不要像这样将令牌粘贴到远程URL中:

https://[email protected]/org/repo.git

这种风格可能通过日志、进程列表、shell历史和配置文件泄露。

对于Jenkins、GitHub Actions运行器、GitLab运行器和类似系统,将凭据存储在平台的秘密机制中,并仅将其注入需要它的作业。

快速检查清单

当你卡住时,按顺序运行这些:

git remote -v
git ls-remote origin

如果URL是HTTPS,清除旧的缓存凭据并使用具有正确仓库权限的当前令牌。

如果URL是SSH,运行:

ssh -T git@your-hostname
ssh -vT git@your-hostname

确认预期的密钥被提供,并且其公钥部分已注册到正确的账户。

如果身份验证成功但push失败,查找授权规则:受保护分支、缺少写角色、过期的SSO授权、只读部署密钥或没有写权限的令牌。

可靠的修复方法不是尝试随机密码。匹配远程协议与凭据类型,移除过时的缓存凭据,直接测试连接,然后检查仓库的权限。