WordPress 一直报”密码不正确”?不一定是密码错了——一次 REST API 认证失败的完整排查实录

前几天遇到一个很诡异的问题:让 AI 工具自动给 WordPress 网站发文章,配置了站点地址、用户名、应用程序密码,结果工具一直报错:

错误:为用户 xxx 指定的密码不正确。

按常理,第一反应就是密码复制错了。于是重新生成一个应用程序密码,用官方的复制按钮,一个字符不落地重新粘贴——还是报密码不正确。

如果你也遇到过这种情况,这篇文章可以帮你省掉两天时间。因为最后发现,密码从头到尾都是对的,错的另有其人。

一、先说结论

导致问题的是网站上装的一个微信小程序插件。它在 WordPress 的 REST 认证链路上加了自己的处理逻辑:当 WordPress 已经用应用程序密码验证成功之后,它又把应用程序密码当成登录密码再校验一遍——应用程序密码当然不等于登录密码,于是校验失败,报出「密码不正确」,把本来已经成功的认证结果硬生生覆盖掉了。

一个「画蛇添足」的钩子,让所有人都在密码本身上打转。

二、排查过程:一步步排除法

第 1 步:确认密码到底对不对

这里有个关键技巧:WordPress 除了 REST API,还有一个老的 XML-RPC 接口,两者用的账号密码可以相同。用同一对账号密码去测 XML-RPC:

  • REST API(/wp-json/)→ 报密码不正确
  • XML-RPC(/xmlrpc.php)→ 认证成功,还能看到返回的管理员权限

同一对凭据,两条通道,一个成功一个失败——这就证明了密码本身没问题,是 REST 这条链路被什么东西污染了。

这一步价值极大:如果当时只在「重新生成密码」上打转,永远解决不了问题。

第 2 步:观察报错的”长相”

仔细看报错文案:「为用户 xxx 指定的密码不正确」——这其实是 WordPress 登录框的报错文案,不是 REST API 应有的错误格式。REST API 正常的未认证错误应该是 401 状态码加「您目前没有登录」。

错误文案出现在了不该出现的地方,说明请求在认证流程里被某段代码拦下来,走了登录校验的逻辑。

第 3 步:做对照实验

继续做了一组实验,结果非常有规律:

请求方式 结果
不带认证头访问 REST API 正常
带错误格式的 Authorization 头 正常
带格式正确的 Basic 认证头(哪怕密码乱填) 一律报「密码不正确」

规律很清晰:只要请求里出现可以解析出「用户名:密码」的 Basic 认证头,就出事;不管密码对错。这基本锁定了问题出在某段接管 Basic 认证的代码上。

第 4 步:代码层排查——却扑了个空

在服务器上用 grep 搜索所有常见的认证相关钩子:

grep -rn --include='*.php' \
  -e 'rest_authentication_errors' -e 'PHP_AUTH_USER' \
  -e 'wp_authenticate' \
  /www/sites/你的域名/wp-content/

按插件名搜索认证类插件——Basic Auth、JWT、Application Passwords……一个都没有。mu-plugins 目录是空的,主题的 functions.php 也干净。

为什么搜不到?因为捣乱插件的名字里根本不含这些关键词。它的目录名是 justweapp——一个和「认证」「Basic」「Auth」毫无关系的名字。这是本次排查最大的教训:按关键词搜索代码,前提是你猜得中关键词。

第 5 步:二分法停用插件

不猜了,直接实验:后台把插件全部停用,问题立刻消失;再逐个启用,启用到小程序插件时问题复现——元凶锁定。

但用户需要保留小程序功能,不能停用插件,于是有了第 6 步。

第 6 步:让网站自己”招供”

用 Code Snippets 插件写了一段诊断代码:把 REST 认证钩子上挂着的所有回调函数和它们的源文件路径,通过一个临时 API 输出出来。结果一目了然:

rest_authentication_errors → WWA_basic_auth_error  (某插件/includes/functions.php:1097)
determine_current_user     → WWA_basic_auth_handler(某插件/includes/functions.php:1047)

正是小程序插件挂上去的两个认证回调。

三、修复:六行代码

既然知道了确切的函数名和优先级,修复就非常干净了——用 Code Snippets 加一段代码,在 REST 初始化前把这两个捣乱的回调摘掉,插件的其他功能(小程序接口)完全不受影响:

add_action( 'rest_api_init', function () {
    remove_filter( 'rest_authentication_errors', 'WWA_basic_auth_error', 10 );
    remove_filter( 'determine_current_user', 'WWA_basic_auth_handler', 20 );
}, 0 );

保存启用后测试:正确密码返回 200,错误密码返回标准的 401,一切回归正常。插件开着,REST 也能用了,鱼与熊掌兼得。

(具体操作步骤和诊断代码的写法,见本站另一篇文章《插件冲突导致 REST API 500?教你用 Code Snippets 精准摘掉捣乱的钩子》)

四、这次排查留下的四条经验

  1. 报「密码不正确」≠ 密码真的错了。交叉验证一下:换个通道(比如 XML-RPC)用同一对凭据测试,一测便知。
  2. 看错误文案的”出身”。登录框的文案出现在 API 报错里,本身就是线索。
  3. 按关键词 grep 会漏掉不叫这个名字的凶手。二分法停用插件是更可靠的兜底手段。
  4. 诊断钩子比猜代码高效得多。让网站自己列出认证链路上挂了谁,比人肉翻代码快 100 倍。

五、写在最后

这类问题的迷惑性在于:报错指向密码,所有人(包括工具的 AI 助手)都会先让你重新生成密码。但当「重新生成密码」第二次仍然失败时,就该换方向了——问题大概率不在凭据,而在站点的认证链路被什么东西接管了。

希望这篇实录能帮你少走两天弯路。

原创文章,作者:小微财服云,如若转载,请注明出处:https://www.779it.com/342.html

赞 (0)
小微财服云小微财服云
上一篇 1天前
WordPress 彻底关闭全站评论教程|无需 Akismet 反垃圾插件
下一篇 15小时前

相关推荐