1. 这条报错到底在说什么
如果你在命令行里往代码托管平台推送代码时,突然看到这么一行红字:remote: Support for password authentication was removed on August 13, 2021.,然后推送直接失败,别慌,这不是你的网络出了问题,也不是仓库坏了,而是平台方在几年前就完成的一次认证策略切换,只是你本地一直用的老办法刚好撞上了这堵墙。
先把结论摆在最前面:从 2021 年 8 月 13 日起,主流的代码托管平台不再接受用账号密码的方式做 Git 操作的鉴权。也就是说,以前你git push时弹出的那个输入用户名和密码的框,现在无论你输得多正确,都会被拒绝。取而代之的是一套基于令牌(Token)或者密钥(SSH Key)的认证机制。
这个变化影响的范围其实比很多人想象的要大。它不只影响git push,还包括git pull、git fetch、git clone私有仓库等所有需要身份验证的远程操作。受影响的用户群体主要是两类:一类是一直用 HTTPS 地址克隆仓库、靠记忆输密码的老用户;另一类是在 CI/CD 流水线、自动化脚本里硬编码了账号密码的工程配置。前者会在交互式操作时被拦下,后者则会在无人值守的构建环节突然报错,排查起来更头疼。
我自己第一次遇到这个报错是在一次给开源项目提 PR 的时候。本地改完代码,git push origin feature-branch,终端直接甩出这行提示,当时第一反应是"我密码打错了?"重试了三次,换了两个终端,甚至重启了机器,才意识到问题根本不在密码上。后来翻了平台的公告才明白,这是认证方式的整体迁移,跟个人操作失误没有半点关系。
所以这篇文章想做的事情很明确:把这条报错背后的来龙去脉讲清楚,把几种可行的替代方案掰开揉碎地对比一遍,然后给出可以直接照着做的操作步骤。不管你是刚接触 Git 的新手,还是维护着一堆自动化脚本的老手,都能在这里找到能落地的解法。文章会覆盖令牌认证、SSH 密钥认证、凭据缓存管理、多账号场景处理,以及自动化环境下的最佳实践,尽量把每个环节的"为什么"也一并说透。
2. 认证方式变更的来龙去脉
2.1 为什么平台要砍掉密码认证
很多人第一反应是"好好的密码为什么不让用了",觉得这是平台在给用户添麻烦。但站在平台和安全的角度看,这个决定其实是被逼出来的。
密码认证最大的问题在于它的可猜测性和可复用性。大量用户在不同平台使用同一个密码,一旦某个小网站发生数据泄露,攻击者拿着这批账号密码去撞库,就能轻松登录代码托管平台。而代码仓库里往往藏着公司的核心资产、私有配置、密钥文件,一旦被攻破,损失远超普通账号被盗。
另一个关键因素是密码无法精细化授权。你给一个自动化脚本配了账号密码,这个脚本就拥有了你账号的全部权限——能读所有仓库、能改所有配置、能删所有分支。你没法限制它"只能读某一个仓库",也没法在它泄露后单独吊销它的权限,只能改密码,而改密码又会把所有用到这个密码的地方全部搞挂。
令牌机制恰好解决了这两个痛点。令牌可以设置细粒度的权限范围(比如只读、只写某个仓库),可以设置过期时间,可以单独吊销而不影响其他令牌,还能在平台的审计日志里看到"哪个令牌在什么时候做了什么操作"。对平台来说,这是安全能力的整体升级;对用户来说,短期是麻烦,长期是保护。
2.2 时间线与你可能踩坑的节点
虽然报错信息里写的是 2021 年 8 月 13 日,但这个变更并不是一刀切的。平台通常会分阶段推进:先发公告、再对部分用户灰度、然后对新建账号强制、最后对存量账号全面生效。这就导致一个现象——有些人早在 2021 年就遇到了,有些人可能到 2022 年甚至更晚才突然撞上。
我见过最典型的踩坑场景是这样的:某台服务器上的部署脚本已经稳定运行了两年,里面写死了账号密码,一直没出过问题。某天运维重启了机器,或者平台那边完成了最后的策略收口,脚本突然开始报这个错,整个发布流程卡死。因为脚本是无人值守的,报错信息又埋在日志里,往往要等到业务方反馈"新版本没上线"才被发现。
还有一种情况是凭据缓存过期。你本地之前输过一次密码,系统把它缓存起来了,所以一段时间内git push都正常。等缓存过期,需要重新输入时,你才发现密码这条路已经走不通了。这种"延迟爆发"最容易让人误以为是偶发故障。
提示:如果你现在还在用账号密码做 Git 鉴权,哪怕暂时没报错,也建议尽快迁移。报错只是时间问题,而且往往在你最不希望它出现的时候出现。
2.3 报错信息的完整解读
这条报错通常不会单独出现,它往往伴随着下面这几行一起刷屏:
remote: Support for password authentication was removed on August 13, 2021. remote: Please see https://<平台文档地址>/articles/cloning-with-https for information on currently recommended modes of authentication. fatal: Authentication failed for 'https://<平台地址>/<用户名>/<仓库名>.git/'逐行拆开看:第一行是平台服务端返回的,明确告诉你密码认证已经下线;第二行是引导你去查官方推荐的认证方式;第三行是 Git 客户端本地的报错,说明这次鉴权整体失败了。
关键点在于,这个错误是服务端主动拒绝的,不是你的网络问题,也不是 Git 版本问题。所以你去升级 Git、换网络、清缓存,统统没用。方向只有一个:换认证方式。
3. 令牌认证:最直接的替代方案
3.1 令牌到底是什么
你可以把令牌理解成一把专门为程序或脚本定制的、可以随时作废的钥匙。它长得像一串随机字符,比如ghp_xxxxxxxxxxxxxxxxxxxx这种格式,本质上是一个长期有效的密码替代品,但比密码多了权限控制和生命周期管理。
创建令牌的入口通常在平台的网页端设置里,路径大同小异:进入账号设置,找到开发者设置或访问令牌相关的菜单,选择生成新令牌。生成时平台会让你勾选权限范围,这一步非常关键,勾多了有安全风险,勾少了操作会失败。
以最常见的代码推送场景为例,你至少需要勾选仓库内容的读写权限。如果你还要操作流水线、管理 Issue、读取用户信息,就得对应勾选相应范围。我的建议是按最小必要原则来:这个令牌只给这一个用途用,只勾它真正需要的权限。
3.2 创建令牌的实操步骤
下面这套流程是我自己反复用过、也帮同事配置过很多次的版本,按顺序做基本不会出错。
- 登录代码托管平台的网页端,进入个人账号的设置页面。
- 找到"开发者设置"或"访问令牌"这一类菜单,点击进入令牌管理页。
- 点击"生成新令牌",给令牌起一个能一眼看懂用途的名字,比如
deploy-server-a或local-macbook-push。 - 设置过期时间。这里有个取舍:设太短,你得频繁更换;设太长,泄露风险大。生产环境建议 90 天,个人开发机可以设 1 年。
- 勾选权限范围。纯推送代码的话,勾选仓库内容读写即可;如果还要操作其他功能,按需追加。
- 点击生成,立刻把令牌复制保存到安全的地方。页面刷新后就再也看不到完整令牌了,只能重新生成。
- 把令牌当作密码使用。当 Git 提示输入密码时,粘贴这个令牌。
第 6 步是新手最容易翻车的地方。我见过不止一个人生成完令牌,切了个窗口回来发现页面刷新了,令牌没了,只能重新生成一遍。所以生成的那一刻,先复制,再干别的。
3.3 令牌怎么用才不别扭
令牌生成后,使用方式和密码几乎一样,但有几个细节要注意。
第一次推送时,Git 会提示输入用户名和密码。用户名填你的账号名,密码处粘贴令牌。如果系统弹的是图形化的凭据输入框,同样在密码栏粘贴令牌。
如果之前缓存过旧密码,需要先清掉缓存,否则系统会一直用旧的错误凭据。不同系统的清理方式不一样:
# macOS,使用系统钥匙串 git credential-osxkeychain erase host=github.com protocol=https # 输入上面三行后按 Ctrl+D # Windows,打开"凭据管理器",找到对应的 Git 凭据删除 # Linux,检查并编辑凭据文件 git config --global --edit # 找到 credential.helper 相关配置,或直接删除 ~/.git-credentials避免每次输入,可以配置凭据缓存。让系统记住令牌一段时间:
# 缓存 1 小时(3600 秒) git config --global credential.helper 'cache --timeout=3600' # macOS 用钥匙串长期保存 git config --global credential.helper osxkeychain # Windows 用凭据管理器 git config --global credential.helper manager注意:
store这种明文保存方式虽然方便,但会把令牌以明文写在磁盘上,多人共用的机器上千万别用。我一般只在完全私人的开发机上才考虑。
3.4 令牌方案的优势与局限
令牌最大的优势是上手快、改动小。你不需要生成密钥对,不需要配置 SSH 配置文件,只要把原来输密码的地方换成令牌就行。对于临时用一下、或者不熟悉命令行的用户来说,这是门槛最低的方案。
但它也有明显的局限。第一,令牌是明文凭据,一旦泄露,拿到的人就能以你的身份操作,直到你发现并吊销它。第二,令牌管理成本不低,如果你有多个账号、多台机器、多个用途,很快就会攒出一堆令牌,过期时间还各不相同,管理起来很烦。第三,在自动化脚本里硬编码令牌,本质上和硬编码密码一样危险,只是换了个形式。
所以令牌适合"快速解决当前问题",但如果你追求更规范、更安全的长期方案,SSH 密钥是更值得投入的方向。
4. SSH 密钥认证:更稳妥的长期选择
4.1 SSH 认证的原理,用大白话讲
SSH 认证的核心是一对密钥:一把私钥,一把公钥。私钥留在你自己机器上,绝不外传;公钥交给代码托管平台保存。
当你用 SSH 方式连接平台时,平台会拿它保存的公钥出一道"数学题",只有对应的私钥才能解出来。你的机器用私钥解出答案发回去,平台验证通过,就确认了你的身份。整个过程私钥从不离开你的机器,也不需要在网络上传输密码或令牌。
这个机制的好处很直接:即使平台的数据库被拖走,攻击者拿到的也只是公钥,没有私钥什么都做不了。而私钥始终在你本地,只要你的机器安全,账号就安全。
4.2 生成与配置密钥的完整流程
下面这套流程适用于绝大多数场景,我按顺序列出来,每一步都说明为什么这么做。
第一步:检查是否已有密钥
ls -al ~/.ssh看看有没有id_rsa、id_ed25519这类文件。如果有,说明你之前生成过,可以直接跳到第三步。如果没有,继续第二步。
第二步:生成新密钥
ssh-keygen -t ed25519 -C "your_email@example.com"这里选ed25519而不是老的rsa,原因是 ed25519 更短、更快、安全性更高,现在的主流平台都支持。-C后面的注释只是用来标识这把钥匙的用途,方便你以后辨认,不影响功能。
执行后会问你保存路径,直接回车用默认的~/.ssh/id_ed25519即可。然后会问你要不要设置密码短语(passphrase)。强烈建议设置,这样即使私钥文件被拷走,没有密码短语也用不了。设置后每次使用需要输入一次,配合 ssh-agent 可以免去重复输入。
第三步:把公钥添加到平台
# 查看公钥内容 cat ~/.ssh/id_ed25519.pub复制输出的整行内容,登录平台网页端,进入 SSH 密钥设置页面,粘贴添加。注意是.pub结尾的公钥文件,千万别把没有.pub的私钥贴上去,那等于把钥匙直接送人。
第四步:测试连接
ssh -T git@github.com如果配置正确,会看到类似"Hi 用户名! You've successfully authenticated"的提示。第一次连接会问你是否信任该主机,输入 yes 即可。
第五步:把仓库地址从 HTTPS 换成 SSH
# 查看当前远程地址 git remote -v # 切换为 SSH 地址 git remote set-url origin git@github.com:用户名/仓库名.git这一步很多人会忘。密钥配好了,但远程地址还是 HTTPS 的,推送时依然走密码认证那条路,照样报错。所以一定要确认地址是git@开头的。
4.3 多账号场景下的密钥管理
如果你同时用个人账号和公司账号,或者有多个平台的账号,就需要管理多把密钥。核心工具是~/.ssh/config文件。
# ~/.ssh/config 示例 Host github-personal HostName github.com User git IdentityFile ~/.ssh/id_ed25519_personal Host github-work HostName github.com User git IdentityFile ~/.ssh/id_ed25519_work配置好后,克隆仓库时用别名代替真实域名:
git clone git@github-personal:用户名/仓库名.git这样 Git 就会根据别名自动选用对应的密钥,不会串号。我一开始不知道这个技巧,两个账号的密钥互相覆盖,推送时经常推错账号,排查了半天才发现是密钥选错了。
4.4 SSH 方案的取舍
SSH 的优势是安全性高、一次配置长期受益、不需要管理一堆会过期的令牌。私钥不出本地,公钥泄露也无所谓,这是它比令牌更让人放心的根本原因。
代价是初始配置稍复杂,尤其是多账号场景,需要理解 config 文件的写法。另外在某些受限的网络环境里,SSH 端口可能被限制,这时候 HTTPS 加令牌反而更稳。所以两种方案不是非此即彼,而是各有适用场景。
我的个人习惯是:开发机用 SSH,自动化脚本和受限环境用令牌。这样既享受了 SSH 的安全,又保留了令牌的灵活性。
5. 自动化环境下的认证处理
5.1 CI/CD 流水线里怎么配
自动化环境是这次认证变更的重灾区。很多流水线脚本里写的是https://用户名:密码@平台地址/仓库.git这种形式,密码认证一停,整条流水线直接挂掉。
正确的做法是用环境变量注入令牌,而不是把令牌写死在脚本里。以常见的流水线配置为例:
# 在流水线的密钥管理里配置一个变量,比如 GIT_TOKEN steps: - name: 拉取代码 run: | git clone https://x-access-token:${GIT_TOKEN}@github.com/用户名/仓库名.git这里x-access-token是占位用户名,实际鉴权靠后面的令牌。令牌从流水线平台的密钥管理里读取,不会出现在代码仓库里,也不会打印在日志中。
注意:一定要确认流水线平台对密钥变量做了日志脱敏。我见过有的平台默认不脱敏,令牌直接明文打在构建日志里,等于公开泄露。
5.2 部署脚本的迁移思路
服务器上的部署脚本迁移,思路和流水线类似,但要多考虑一层令牌的存放位置。
不推荐的做法是把令牌写在脚本文件里,因为脚本可能被备份、被同步、被其他人看到。推荐的做法是放在只有对应服务账号能读的环境文件里:
# /etc/deploy/env,权限设为 600,只有 root 或服务账号可读 GIT_TOKEN=ghp_xxxxxxxxxxxx脚本里这样引用:
source /etc/deploy/env git clone https://x-access-token:${GIT_TOKEN}@github.com/用户名/仓库名.git这样令牌和脚本分离,脚本可以进版本库,令牌不会。轮换令牌时也只改环境文件,不用动脚本。
5.3 令牌轮换与过期管理
令牌设了过期时间,到期就会失效,自动化任务会突然报错。所以必须建立轮换机制,不能等它过期了才手忙脚乱。
我的做法是给每个令牌建一条记录,写清楚用途、创建时间、过期时间、负责人。在日历上提前一周设提醒,到期前生成新令牌、更新环境文件、验证任务正常、再吊销旧令牌。整个过程平滑过渡,不会出现空窗期。
如果令牌已经过期导致任务失败,处理顺序是:先生成新令牌,再更新所有引用它的地方,最后确认任务恢复。不要急着删旧的,万一有新令牌没覆盖到的地方,旧的还能临时顶一下。
6. 常见问题与排查速查
6.1 高频问题对照表
| 现象 | 可能原因 | 解决方向 |
|---|---|---|
| 推送报密码认证已移除 | 远程地址是 HTTPS 且用密码 | 换令牌或改 SSH |
| 令牌粘贴后仍失败 | 权限范围没勾对 | 检查令牌权限 |
| 改了 SSH 还是报错 | 远程地址没换 | git remote set-url |
| 多账号推送串号 | 密钥选择错误 | 配置 ssh config |
| 流水线突然失败 | 令牌过期 | 轮换令牌 |
| 提示权限被拒绝 | 公钥没添加或加错 | 重新添加公钥 |
6.2 几个容易忽略的坑
坑一:令牌权限勾少了。有人只勾了读权限,结果推送失败,报的还是认证错误,容易误以为是令牌本身有问题。其实推送需要写权限,创建令牌时一定要看清楚。
坑二:SSH 地址写错。git@github.com:用户名/仓库.git这个格式里,冒号后面直接跟用户名,不是斜杠。写成git@github.com/用户名/仓库.git就会失败。这个细节我第一次配的时候也踩过。
坑三:凭据缓存没清。换了令牌,但系统还在用缓存的旧密码,一直报错。这时候要主动清缓存,而不是反复重试。
坑四:私钥权限太开放。SSH 对私钥文件权限有要求,如果权限是 644(其他用户可读),会直接拒绝使用。正确权限是 600:
chmod 600 ~/.ssh/id_ed25519坑五:代理配置干扰。有些环境配了 Git 代理,导致 SSH 连接走错路径。检查git config --global --get http.proxy,如果有不需要的代理配置,清掉。
6.3 排查的通用思路
遇到认证问题,我一般按这个顺序排查:
- 确认远程地址类型:
git remote -v,看是 HTTPS 还是 SSH。 - 确认认证方式匹配:HTTPS 配令牌,SSH 配密钥,别搞混。
- 确认凭据有效:令牌没过期、权限够;密钥没被删、权限对。
- 确认缓存干净:清掉旧凭据,避免干扰。
- 看完整报错:不要只看最后一行,前面的提示往往才是根因。
这套顺序能覆盖九成以上的认证问题。剩下的一成通常是环境特殊,比如公司网络限制、平台侧策略调整,那就需要结合具体报错再分析。
7. 我踩过的坑和几点体会
第一次遇到这个报错时,我的处理方式是错的——反复重试、换网络、升级 Git,折腾了快一个小时才想起来去搜报错原文。后来复盘,最大的教训是:看到明确的报错信息,先读完整,再动手。那行红字其实已经把原因和解决方向都写清楚了,是我自己没耐心看。
第二个体会是令牌和密钥要尽早配,别等报错。我现在每台新机器、每个新账号,第一件事就是把 SSH 密钥配好,把令牌该建的建好。这样永远不会在赶着发布的时候被认证问题卡住。
第三个是关于自动化环境的令牌管理。我曾经在一个部署脚本里硬编码了令牌,后来令牌过期,脚本挂了,排查时才发现令牌散落在好几个地方,改起来特别麻烦。从那以后我坚持令牌集中存放、集中轮换,脚本里只引用变量。
最后一个建议:定期检查你的认证配置。令牌有没有快过期的,密钥有没有该换的,远程地址有没有还是老 HTTPS 的。这些检查花不了几分钟,但能避免很多突发故障。认证这件事,平时不起眼,出问题的时候往往最耽误事。