资讯详情

Git克隆认证失败?从账号密码到SSH Key的完整排障指南

📅 2026/10/18 18:09:44 | 华诺云谱 👁 阅读
Git克隆认证失败?从账号密码到SSH Key的完整排障指南
1. 从一次克隆失败说起问题到底出在哪一环如果你也经历过这种场景在终端里敲下git clone本来等着代码哗啦啦落盘结果屏幕上弹出一整段刺眼的红色报错那一刻的挫败感做过版本控制的人都懂。我最近就因为在 GitHub 上克隆一个新仓库把账号密码、Token、SSH Key 这条路从头到尾走了一遍。过程不算顺利但正因为卡了壳我才把之前几个一直似懂非懂的点彻底弄明白了。这篇排障实录不打算写成教科书就按我当时排查的真实顺序把每一步为什么这么做、报错到底在说什么、怎么修原原本本记下来。如果你也遇到过类似问题可以直接对照自己的情况抄作业。1.1 事发当天的完整报错记录当时我拿到一个仓库地址第一反应就是用 HTTPS 方式克隆。仓库本身是内部协作项目URL 长这样https://github.com/some-org/example-repo.git命令敲下去之后终端开始正常地询问用户名和密码$ git clone https://github.com/some-org/example-repo.git Cloning into example-repo... Username for https://github.com: myusername Password for https://myusernamegithub.com:到这里一切都还很正常直到我输入了 GitHub 的登录密码并且按下回车。接下来的输出让我愣了一下remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead. remote: Please see https://github.com/settings/tokens for more information fatal: Authentication failed for https://github.com/some-org/example-repo.git/我当时的第一个反应是这仓库的权限有问题还是我密码记错了于是我反复确认用户名、重新输入密码结果还是一模一样的报错。这种看起来是密码错但你知道密码没错的体验我相信不止我一个人碰到过。其实问题根本不在密码而在于这个年代已经不允许你拿密码去执行 Git 操作了。1.2 我第一次排查时理解的偏差当时我对 Git 鉴权的理解还停留在HTTPS 就是账号加密码SSH 就是密钥这个层面。所以一报错我自然以为是仓库权限、网络、或者密码大小写的问题。实际上这条报错已经说得很直白了Support for password authentication was removed——意思是这个通道本身已经被关闭而不是你的凭证写错了。这个理解偏差其实很典型。很多人搭建 Git 环境的时间不同接触到的默认行为也不同。早几年 GitHub 确实允许直接用账号密码去拉取和推送网上大量教程也是这么教的。但当平台策略调整之后那些旧教程就成了误导源。这次排障给我的第一个教训就是遇到鉴权类报错先读报错正文里remote:开头的那几行平台通常会把真正的原因直接告诉你而不是盯着fatal那一行瞎猜。2. 为什么账号密码这一套彻底走不通了2.1 密码认证被移除的来龙去脉GitHub 从 2021 年 8 月 13 日开始全面移除了对账号密码的 Git 操作认证。也就是说你在克隆、推送、拉取时输入的那个密码已经不再是你的账号密码本身而必须是一个叫 Personal Access Token个人访问令牌的东西。平台还给了宽限期但到期之后就是硬性关闭无论你密码输得多熟练都不会再被接受。为什么要把密码从这套流程里踢出去核心原因是安全模型的问题。你想想如果所有 Git 操作都用同一个账号密码来做那这个密码一旦泄露等于把整个账号的读写权限、个人信息、私有仓库、甚至后续操作的入口全交出去了。而且密码是长期有效的你很难在发现泄露之后及时止损。令牌的思路完全不同它可以单独生成、单独设置权限范围、单独设定过期时间还能随时一键撤销。哪怕某个令牌泄露损失的只是这一个令牌对应的那部分权限其他功能不受影响。这和你用备用钥匙开一扇门、丢了大不了换那把锁是同一个逻辑。说白了这不只是某个平台的行为而是整个行业的趋势。你去看看其他代码托管平台、云服务商的开发接口几乎都在朝细粒度凭证 短期有效性这个方向走。Git 本身只是一个客户端工具它不关心你给它的是密码还是令牌只要凭证能被服务端认可就行。所以问题从来不是Git 怎么了而是GitHub 的认证策略变了。2.2 Personal Access Token 的正确生成姿势如果你暂时不想折腾 SSH Key那最快的解法就是生成一个令牌来替代密码。操作路径如下登录 GitHub 后点击右上角头像进入 Settings。在左侧菜单最底部找到 Developer settings。进入 Personal access tokens我建议直接用 Fine-grained tokens 按需创建但很多人第一次接触时用 Tokens (classic) 更容易上手。点击 Generate new token给它起一个能辨认用途的名字比如laptop-2025-clone。在权限勾选里如果只是克隆公开或私有仓库勾选repo范围就够如果要推送代码同样需要repo如果涉及到 Actions 相关操作才需要workflow权限。点击生成之后页面只会给你展示一次令牌内容形如ghp_开头的一长串字符。复制并保存好一旦关掉页面就再也看不到了。使用方式有两种。第一种是临时性的在 Git 提示输入密码时不输账号密码而是把用户名填上你的 GitHub 用户名密码处粘贴这个令牌。第二种是长期性的把令牌交给 Git 的凭据管理器保存之后就不用重复输入了$ git config --global credential.helper store执行之后再克隆一次输入一次令牌Git 就会把凭证以明文形式存在~/.git-credentials文件里。注意这里是明文所以个人电脑上要保证这个文件不被别人读到。更稳妥一点的做法是用系统自带的凭据管理器比如 macOS 的 keychain 或 Windows 的 Credential Manager可以通过credential.helper osxkeychain或 Windows 自带的 Git Credential Manager 来配置。2.3 用 Token 时最容易踩的三个坑第一个坑是权限勾选不够。比如只勾了read类权限就去推代码克隆能成功但 push 的时候会被拒绝。报错可能会让你误以为是网络问题或分支保护规则实际上只是令牌权限不够。我的经验是拿不准的时候先按最小够用原则来克隆就只克隆推送就把repo勾上然后缺什么补什么。第二个坑是令牌只能看一次。不少人生成完直接复制到终端关掉页面之后找不到备份只能重新生成一个。这不算什么致命问题但会打断思路。我的习惯是生成之后立即存到本机密码管理器里命名带上下次提醒比如GitHub-clone-token 有效期30天。第三个坑是忘记看有效期。经典令牌可以设置永久有效或者最长一年细粒度令牌往往要手动设过期时间。过期之后 Git 会报 401 或者直接提示认证失败很多人的第一反应是是不是被封号了实际上只是令牌到期。所以排查时可以把令牌有效期作为一个重点怀疑对象。到这里账号密码这条线算是彻底弄明白了。但我在实际操作中很快发现另一个问题Token 方案虽然能用可我每天要频繁执行 push、pull 操作每次都要操心令牌的权限和有效期总觉得不够顺手。于是我把目光转向了 SSH Key——也就是这次排障的最终归宿。3. 切换 SSH Key 之前的方案对比与原理补课3.1 HTTPS 与 SSH 两种克隆协议怎么选既然要切换方案那就先得把两者放在一起比一比。很多新手只知道能用就行但选错协议会直接影响后续的使用体验和维护成本。对比维度HTTPS 克隆SSH 克隆克隆地址示例https://github.com/org/repo.gitgitgithub.com:org/repo.git认证方式用户名 Token公钥/私钥对首次配置成本低生成 Token 即可略高要生成密钥并登记公钥日常使用体验可能反复输凭证或依赖凭据管理器配置一次后基本免密凭证失效风险Token 会过期、需要续期私钥不换就一直有效安全粒度令牌可按权限、按仓库授权一个私钥通常对所有可见仓库生效从表格可以看出HTTPS 的优势是首次成本低适合偶尔用一次、或者在一台临时机器上快速拉取代码。而 SSH 的优势是一劳永逸配置好之后几乎感受不到认证过程的存在。我当时选择 SSH还有一个更实际的原因我的日常操作里有大量命令和脚本它们会以非交互方式执行git push。HTTPS 模式下如果令牌过期或者没存进凭据管理器脚本就会卡在认证提示那一步。而 SSH 只要私钥在、权限对脚本执行起来从来不用操心凭证问题。如果你也有大量自动化脚本SSH 几乎是必选项。当然SSH 也有自己的注意点私钥就是一串能证明你身份的凭证谁拿到它谁就能冒充你操作仓库。所以私钥本身的保管比令牌还要上心后面我会专门说到权限设置。3.2 公钥私钥对是怎么完成免密认证的在没有真正配过 SSH Key 之前我一直以为它就是把两个文件放好Git 自己认人。后来仔细看了一遍它的工作流程才发现它背后是一套非常经典的非对称加密原理只是 Git 把它封装得让人无感了。非对称加密的特点是密钥不是一把而是一对分为公钥和私钥。公钥可以随便发给别人、放在服务器上私钥必须自己藏好绝不能外传。这两把钥匙的关系可以简单理解成用公钥加密的内容只有对应的私钥能解开反过来持有私钥的人能证明自己拥有这把私钥而验证方只需要用公钥做一次校验不需要知道私钥本身。放到 GitHub 场景里整个认证流程是这样的你在本地生成一对密钥把公钥内容粘贴到 GitHub 的设置页面。之后每次执行git clone或git pushGit 会通过 SSH 协议连接 GitHub。服务器看到一个连接请求不会直接拒绝而是抛出一道证明题你是不是真的持有与这个公钥配对的私钥Git 客户端会调用本地私钥完成签名然后把签名结果发给服务器。服务器用之前登记的公钥去验证签名验证通过就放行。整个过程里私钥始终没有离开过你的机器网上传输的只是一次性的签名验证数据。这样设计的精妙之处在于你不需要给服务器提供任何密码服务器也不存储你的私钥它只靠公钥做数学校验。即使公钥被人偷走也无法反推出私钥更无法冒充你。这也是为什么公钥可以大大方方地贴在 GitHub 上而私钥文件看一眼都要紧张的原因。原理补完课之后剩下的就是动手。我当时以为 SSH 的配置比 Token 复杂得多结果真正操作下来反而比想象中顺畅。下面把完整流程一步一步拆开写。4. SSH Key 生成、登记与首次连接的全流程4.1 密钥算法选型ed25519 对比 RSA生成密钥之前首先要选算法。网上老教程基本都让你用 RSA并且强调位数要到 4096。但在我个人看来新环境直接上 ed25519 才是更合理的选择。ed25519 是目前 OpenSSH 默认推荐的算法之一它的优势有几个密钥长度短、生成速度快、安全性高并且从 OpenSSH 6.5 开始就被支持。在 GitHub 官方文档里ed25519 也是被明确推荐的选项。RSA 4096 的优势主要是兼容性——一些特别老的服务器、交换机或者旧系统可能只认 RSA。但如果你只是正常连 GitHub不涉及那些远古环境ed25519 完全够用。判断方法很简单你在终端执行ssh -V看版本号如果 OpenSSH 版本是 7.0 以上就可以放心用 ed25519。除非你明确知道自己需要兼容某台老设备否则别在 RSA 上纠结。4.2 一次完整的 ssh-keygen 实操记录生成密钥的命令总共就一行但有些参数值得解释一下ssh-keygen -t ed25519 -C your_emailexample.com-t指定算法类型这里填的是 ed25519。-C是给密钥加一条备注信息通常填邮箱也可以填任何能帮你识别这把钥匙来源的文字比如laptop-2025。这个备注会写进公钥文件的末尾纯粹是给自己看的不影响认证结果。执行之后会问你要把密钥保存在哪里默认路径是~/.ssh/id_ed25519。如果这是你的第一把密钥直接回车用默认路径就行。如果你已经有一把密钥了那要手动改成新名字比如~/.ssh/id_ed25519_work避免覆盖旧密钥。紧接着它会问你是否设置 passphrase口令短语。这一步我强烈建议不要留空尤其是用在笔记本之类的移动设备上。passphrase 相当于给私钥加了一道本地保险即使有人偷走了你的私钥文件没有这个口令也解不开。当然它也有代价——每次 SSH 连接都可能让你输入一次口令这时候就需要 ssh-agent 来缓解后面细说。实操输出大致长这样$ ssh-keygen -t ed25519 -C devexample.com Generating public/private ed25519 key pair. Enter file in which to save the key (/home/you/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/you/.ssh/id_ed25519 Your public key has been saved in /home/you/.ssh/id_ed25519.pub The key fingerprint is: SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx devexample.com执行结束后~/.ssh目录下会出现两个文件id_ed25519是私钥id_ed25519.pub是公钥。私钥文件必须放在自己手里公钥文件则随时准备给别人看。注意一下如果你用 Windows默认路径通常在C:\Users\你的用户名\.ssh\下逻辑完全一样。4.3 公钥登记与 ssh -T 首次验证公钥生成之后要用cat命令把它读出来并复制cat ~/.ssh/id_ed25519.pub输出的内容是一长串以ssh-ed25519开头的文本结尾是你的备注。把这整行复制下来然后回到 GitHub 的 Settings → SSH and GPG keys → New SSH key标题随便填比如我的主力电脑Key 类型就选 Authentication Key然后把刚才复制的内容粘贴进去保存。登记完成之后关键的一步来了测试连接。GitHub 给的官方测试命令是ssh -T gitgithub.com我第一次执行时其实有点紧张担心又冒出一堆看不懂的输出。结果正常情况下它返回的是The authenticity of host github.com (xx.xx.xx.xx) cant be established. Are you sure you want to continue connecting (yes/no/[fingerprint])?这里输入yes回车。它的意思是你本机之前没连过 GitHub不知道这台服务器的指纹是否可信问你认不认。输入yes之后GitHub 会把服务器公钥写进本机的~/.ssh/known_hosts以后就不会再问了。跳过这一步直接选no的话连接会被中断。继续往下如果一切配置正确你会看到Hi yourusername! Youve successfully authenticated, but GitHub does not provide shell access.这句话看起来有点怪但它是成功的意思。GitHub 那个 SSH 通道只用来跑 Git 操作不给你开交互式终端所以它专门加了一句不提供 shell 访问。看到这句话就说明密钥认证已经没问题了接下来把克隆地址换成 SSH 格式git clone gitgithub.com:some-org/example-repo.git这次不会再弹出任何认证提示代码直接开始落盘。那一刻前面卡了一个下午的挫败感基本就消掉了。4.4 多 GitHub 账号场景下的 config 配置如果你只用一个 GitHub 账号上面的流程已经足够。但对不少开发者来说工作和个人用的是两个账号甚至还有公司内网的 GitLab。这时候就会出现一个问题~/.ssh/id_ed25519只有一把默认私钥Git 连接 GitHub 时默认只会用它那另一个账号的公钥怎么办解法是在~/.ssh/下创建一个 config 文件手动指定不同域名或别名对应不同私钥。先按前面的方法生成第二把密钥命名为id_ed25519_personal然后把公钥登记到个人账号下。接着创建配置Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes Host github-personal HostName github.com User git IdentityFile ~/.ssh/id_ed25519_personal IdentitiesOnly yes这一段里最关键的参数是IdentitiesOnly yes。它的作用是告诉 SSH访问这个 Host 时只尝试列表里指定的私钥不要把所有私钥都轮询一遍。如果没有这个参数SSH 会把你~/.ssh下的所有密钥挨个拿给服务器试GitHub 端只要发现某个公钥匹配就按那个账号的身份放行——这很容易导致你用个人私钥连上了工作仓库、身份却对不上。配置完成之后克隆工作仓库时用默认的gitgithub.com:org/repo.git克隆个人仓库时把地址稍作修改变成git clone gitgithub-personal:yourname/another-repo.git这个别名机制在处理双账号时非常实用。我排障排到这一步时其实还发现了一个更隐蔽的问题就算密钥全配对了某些环境下的 SSH 连接依然会失败而且报错信息五花八门。于是整个排障进入第五个阶段——系统性梳理那些藏着掖着的坑。5. 换到 SSH 之后仍然失败的排障记录5.1 高频报错与对应处理速查表就算你严格按照上面的流程走SSH 连接仍然有可能失败。我自己在配置过程中就遇到了好几次而且每次报错都长得很像。为了方便对照我把高频报错整理成了一张速查表排查时按图索骥比从头翻日志要快得多。报错信息核心原因对应处理Permission denied (publickey)服务端没有对应公钥或客户端没提供正确私钥确认公钥已登记确认用的是正确私钥确认IdentitiesOnly配置正确gitgithb.com: Permission denied (publickey)克隆地址里的域名拼写错误检查 URL 是不是多了一个字母改成gitgithub.comHost key verification failed本机 known_hosts 没有该主机指纹或指纹已更新首次连接输入 yes若之前连接过删除 known_hosts 里的旧记录重新连接ssh: connect to host github.com port 22: Connection refused防火墙或网络环境屏蔽了 22 端口改用 443 端口连接 SSH配置见下文Agent admitted failure to signssh-agent 里没有加载对应私钥执行ssh-add ~/.ssh/id_ed25519重新加载Load key /home/you/.ssh/id_ed25519: error in libcrypto私钥文件损坏或加密方式不被兼容检查私钥文件是否完整必要时重新生成这六类是我见过最多的。前两类属于配置问题后几类分别牵涉端口、known_hosts 和密钥代理每一个都值得单独展开说。5.2 权限设置、known_hosts 与 ssh-agent 的隐藏坑先说权限。很多人在 Linux 或 macOS 上配置 SSH 时报Permission denied (publickey)排查下来发现原因居然只是~/.ssh目录或私钥文件的权限太开放。SSH 出于安全考虑要求私钥文件不能被其他用户读写。正确权限是目录~/.ssh是 700私钥文件是 600公钥文件是 644。chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519 chmod 644 ~/.ssh/id_ed25519.pub这个坑很像什么就像你家的门锁本身没坏但你把钥匙挂在了门外谁都看得到的地方安保系统直接判定这户不安全。修好权限之后报错瞬间消失。再说 known_hosts。这个文件记录了你曾经连接过的主机指纹作用就是防止中间人攻击。如果你连接时遇到Host key verification failed一般有两种可能要么这是你第一次连这台主机要么 GitHub 服务器的密钥指纹真的变了。前者输入yes即可后者需要把旧记录删掉。查找和删除的命令如下ssh-keygen -R github.com执行之后known_hosts 里所有指向 GitHub 的旧记录都会被移除下次连接时会重新写入并询问一次。然后是 ssh-agent。前面我提到私钥可以设置 passphrase但每次连接都输入一次确实烦人。ssh-agent 就是来解决这个矛盾的它启动后常驻后台你用ssh-add把私钥加载进去第一次需要输入 passphrase之后只要 agent 还活着SSH 就会自动调用它完成签名不再重复询问。eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519macOS 上还可以配合钥匙串访问把 passphrase 存入钥匙串ssh-add --apple-use-keychain ~/.ssh/id_ed25519要注意的是如果重启电脑agent 会清空已加载的密钥。要是此时执行 Git 操作报Permission denied往这个方向想往往比去改 GitHub 设置要靠谱得多。5.3 用 ssh -v 从逐行日志里定位根因如果速查表没有覆盖你的情况那就要拿出最后的排查手段抓详细日志。ssh -vT gitgithub.com-v参数会让 SSH 输出整个握手过程的所有细节比正常模式啰嗦得多但每一次失败的原因都藏在里面。我自己的习惯是先跑一遍然后把输出里几个关键行找出来。第一类关键行是debug1: Offering public key。这表示客户端正在尝试把某个私钥提交给服务器。如果你看到这一行后面紧跟着debug1: Authentications that can continue: publickey说明服务器拒绝了这个私钥对应的公钥——大概率是公钥没登记或者登记在别的账号下了。如果连Offering这行都看不到说明客户端根本没想要用私钥问题可能出在 config 文件的 IdentityFile 路径或者 Host 匹配上。第二类关键行是debug1: Server accepts key。看到这行说明服务器已经认可了你的公钥后面的流程会直接走向认证成功。如果卡在这一行之前那就可以确信是密钥匹配层面的问题而不是网络问题。第三类关键行是连接阶段的连接状态比如debug1: Connecting to github.com port 22。如果这里出现超时或者Connection refused那问题就不在密钥而在网络或端口上。对于端口被屏蔽的情况GitHub 官方早就提供了一个绕开 22 端口的方案连接ssh.github.com的 443 端口。可以在~/.ssh/config里这样写Host github.com HostName ssh.github.com Port 443 User git IdentityFile ~/.ssh/id_ed25519443 端口是 HTTPS 的标准端口大多数防火墙都会放行所以这种方法在公司网络和校园网环境下特别管用。我遇到过不止一次换了 443 端口之后原本死活连不上的 SSH 一下就通了。这种问题在出差、连公共 WiFi 时尤其常见值得记在心里。6. 这轮排障过后我养成的几个 Git 使用习惯技术问题解决之后真正沉淀下来的其实是几个使用习惯。这次从账号密码到 SSH Key 的完整排障让我意识到很多卡壳并不是因为某个单独环节有多难而是因为认知还停留在旧版本里。这里分享几个我事后认真思考过的习惯也算是这次排障的延伸收获。第一个习惯是新机器上默认先配 SSH而不是等着 HTTPS 提示输入密码。哪怕只是临时拉一个仓库我也会先把公钥登记好。配置一次的成本大约三分钟换来的是之后所有 Git 操作都不再被认证流程打断。如果只是偶尔在一台公用机器上拉个代码那我会用 HTTPS 加短时效 Token用完就撤销绝不在公共机器上保存任何默认私钥。第二个习惯是给私钥设置 passphrase并用 ssh-agent 管理而不是图省事直接留空。特别是笔记本这种容易丢失的设备私钥文件只要落进别人手里没有 passphrase 就等于裸奔。虽然每次开机要ssh-add一次有点麻烦但和泄露仓库代码的风险比起来这点麻烦完全不值一提。第三个习惯是定期检查本机所有已登记的 SSH 公钥和 Token。GitHub 的设置页面里可以看到所有生效的密钥和令牌每隔一段时间翻一遍把自己已经不用或者不再信任的凭证删掉。公钥和 Token 更像是钥匙钥匙太多哪天丢了哪把你都不知道这才是真正让人夜里睡不安稳的事。我在这次排障之后就把一台旧机器上遗留的一把三年没用过的公钥彻底清理了。最后一个建议其实很简单遇到任何鉴权报错先花 30 秒看一眼完整报错的正文再动手去查配置。Git 和 GitHub 的报错信息比大多数软件都要友好它们通常已经告诉你该去哪里改、怎么改。真正浪费时间的往往是我们凭借旧经验去猜而不是相信眼前已经写得很清楚的提示。把这套流程走完一遍之后再遇到类似问题基本不会再慌了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑