标签: 后端

  • 三种方式登录 WordPress REST API:Basic Auth、Application Password 与 Cookie Nonce

    三种方式登录 WordPress REST API:Basic Auth、Application Password 与 Cookie Nonce

    上周我想写个脚本把小说章节批量发布到博客,第一道坎就是认证:怎么让脚本以「我」的身份登录?WordPress REST API 官方支持好几种认证方式,但在我的站点(WordPress 7.1 + OpenResty + PHP 8.3,纯 HTTP 无 HTTPS)上实测,只有一种走得通。这篇文章记录完整过程、对比和最终方案。

    一、Basic Auth:看起来最省事,实测 401

    最直观的方式:把用户名密码放进 HTTP 的 Authorization 头。

    curl -u 用户名:密码 \
      http://你的站点/wp-json/wp/v2/users/me
    

    很多教程说这种方式在非 SSL 站点可用,于是我先试了它。结果是 401:

    {
      "code": "rest_not_logged_in",
      "message": "您目前没有登录。",
      "data": { "status": 401 }
    }
    

    我排除了「密码里特殊字符」这个变量——手工把 Base64 头拼出来再发一次,还是 401。这个错误是 WordPress REST 的标准错误结构,说明请求确实到了 WordPress 核心,只是认证没被接受。结论:我的站点当前环境不接受这种认证方式,可能是宿主反向代理或安全策略拦了 Authorization 头,也可能是这套核心/插件组合没有启用它。原因不重要,重要的是生产流程不要依赖它。

    二、Application Password:官方推荐,但要求 HTTPS

    这是 WordPress 团队最希望你用的方式:

    1. 后台 → 用户 → 个人资料
    2. 拉到最下面「应用程序密码」一节
    3. 输入一个名字(比如 publish-script),点创建,会得到一串 xxxx xxxx xxxx xxxx xxxx xxxx 格式的密码

    用法和 Basic Auth 一样,只是密码换成它:

    curl -u 用户名:xxxx-xxxx-xxxx-xxxx-xxxx \
      https://你的站点/wp-json/wp/v2/posts
    

    好处很实在:它是独立凭证,可随时吊销,不会暴露你的登录密码,官方文档也把它作为首选。但有一个硬条件:只在 HTTPS 下生效。我的博客目前是纯 IP + HTTP 访问,建了也用不了。所以这一条被我记进了待办:等域名和证书下来,认证整体迁过去。

    三、Cookie + X-WP-Nonce:最终采用的方案

    第三种方式的原理和浏览器一致:先用登录表单拿到会话 Cookie,之后每次 REST 请求带上 Cookie 加一个时效性 nonce。完整流程四步:

    1. GET /wp-login.php —— 这一步最容易被忽略。WordPress 在这个页面会种一个 test cookie,跳过它直接 POST,会收到「Cookies 被阻止或者您的浏览器不支持」
    2. POST /wp-login.php(提交 log、pwd、testcookie)——成功后拿到 wordpress_logged_in_* 会话 Cookie
    3. GET /wp-admin/post-new.php(任意加载了区块编辑器的后台页面)——页面源码里有一个 wpApiSettings JS 对象,其中的 "nonce" 字段就是需要的 X-WP-Nonce
    4. 每次 REST 请求带上 Cookie + X-WP-Nonce

    PowerShell 核心实现(.NET HttpClient 会自动管理 Cookie 容器):

    $handler = New-Object System.Net.Http.HttpClientHandler
    $client  = New-Object System.Net.Http.HttpClient($handler)
    
    # 1) 先 GET 登录页(拿 test cookie)
    $null = $client.GetAsync('http://site/wp-login.php').GetAwaiter().GetResult()
    
    # 2) POST 登录
    $body = 'log=user&pwd=' + [uri]::EscapeDataString($pass) + '&testcookie=1'
    $content = New-Object System.Net.Http.StringContent(
        $body, [System.Text.Encoding]::UTF8, 'application/x-www-form-urlencoded')
    $null = $client.PostAsync('http://site/wp-login.php', $content).GetAwaiter().GetResult()
    
    # 3) 从后台页面取 nonce
    $admin = $client.GetAsync('http://site/wp-admin/post-new.php').GetAwaiter().GetResult()
    $html  = $admin.Content.ReadAsStringAsync().GetAwaiter().GetResult()
    $nonce = ([regex]::Match($html, '"nonce"\s*:\s*"([a-f0-9]+)"')).Groups[1].Value
    
    # 4) 调 API
    $req = [System.Net.Http.HttpRequestMessage]::new('GET', 'http://site/wp-json/wp/v2/users/me')
    $req.Headers.Add('X-WP-Nonce', $nonce)
    $me = $client.SendAsync($req).GetAwaiter().GetResult()
    

    两个注意点:

    • nonce 有时效窗口。默认 tick 是 15 分钟,一个 nonce 在「当前 + 上一」两个窗口内(约 30 分钟)可重复使用。批量任务很快跑完,一次 nonce 够用;长任务要在过期前重新取一次
    • 如果用 PowerShell 的 Invoke-WebRequest -WebSession,注意 Cookie 集合解析可能不稳定(我实测拿到过名字、值全空的 Cookie)。换成 .NET HttpClient 自带的 Cookie 容器更稳

    四、三种方式对比

    方式 需要 HTTPS 脚本友好度 凭证生命周期 在我站的结论
    Application Password 可长期,随时吊销 首选(等证书)
    Cookie + Nonce nonce 约 30 分钟,cookie 按设置 当前在用
    Basic Auth 理论不需要 实测 401,不可用

    五、结论

    • 站点有 HTTPS:直接 Application Password。凭证可吊销、不暴露登录密码,官方推荐
    • 像我这样纯 HTTP、本机自动化:Cookie + Nonce 可行。本质是把浏览器登录过程脚本化
    • Basic Auth:当调试时的快捷手段用,别在正式流程里赌它

    完整的发布脚本在下一篇(开发实战分类)讲:内容清洗、幂等设计,以及路上踩的坑。

  • 从零开始构建一个 RESTful API

    从零开始构建一个 RESTful API

    RESTful API 是现代 Web 开发中最常用的接口设计风格。本文将用 Python + FastAPI 从零构建一个完整的 RESTful API。

    (更多…)

  • Python 异步编程入门:从 async/await 说起

    Python 异步编程入门:从 async/await 说起

    异步编程是现代编程中不可或缺的一部分。Python 3.5 引入的 async/await 语法让异步代码写起来像同步代码一样直观。

    (更多…)