使用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 denied 或 403 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.com 或 git: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_ed25519、id_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授权、只读部署密钥或没有写权限的令牌。
可靠的修复方法不是尝试随机密码。匹配远程协议与凭据类型,移除过时的缓存凭据,直接测试连接,然后检查仓库的权限。