返回

Python/FastAPI 验证 WordPress 密码 (含 phpass 方案)

python

搞定 Python FastAPI 与 WordPress 用户登录:密码 Hashing 对接指南

你在用 Python (特别是 FastAPI) 构建一个 API,想让你的 WordPress 网站用户也能通过这个 API 登录,比如从移动 App 登录?这想法挺酷!但你可能马上就碰到了钉子:WordPress 的密码怎么在 Python 里进行校验?用 passlib.phpass 好像有点眉目,但对着 wp-config.php 里一堆 KEYSALT 常量,还是不知道怎么下手。

别急,这确实是个常见的坑。这篇文章就带你弄明白 WordPress 密码验证这回事,并给出几种在 Python API 里实现对接的方法。

WordPress 密码 Hashing 的小麻烦

如果你直接看 WordPress 数据库里的 wp_users 表,你会发现 user_pass 字段里的密码字符串长得有点怪,通常类似 $P$Bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 这样。

这玩意儿不是简单的 MD5 或者 SHA1。WordPress 使用的是一个叫做 phpass (Portable PHP Password Hashing Framework) 的库来处理密码。它的特点是:

  1. 迭代哈希 (Iterative Hashing): 它不是只哈希一次,而是进行多轮哈希计算,增加破解难度。
  2. 加盐 (Salting): 每个密码都会使用一个独一无二的随机 "盐" (salt) 来参与哈希计算。这个盐会和哈希结果一起存储(就是上面那个 $P$B 字符串的一部分)。这样一来,就算两个用户设置了相同的密码,它们在数据库里存储的哈希值也是完全不同的。

重点来了: 你在 wp-config.php 里看到的 AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY 以及对应的 SALT 值,它们主要是用来加固 Cookie 和 Nonce (一次性令牌) 的安全性,并不直接用于 phpass 对用户密码本身进行哈希计算 。这是一个非常容易搞混的地方!phpass 使用的盐是为每个密码单独生成并存储在密码哈希字符串里的。

WordPress 怎么验证密码的?

理解 WordPress 自身的验证流程是解决问题的关键。当用户在 WordPress 登录页面输入密码时,后台大致是这么工作的 (核心函数是 wp_check_password()):

  1. 获取存储的哈希: 根据用户名,从数据库 wp_users 表里读出 user_pass 字段的值,也就是那个 $P$B... 字符串。
  2. 提取信息: 从这个存储的哈希字符串中,phpass 能够解析出当初使用的 盐 (salt)迭代次数 (iteration count) 。这些信息就嵌在哈希值里面。
  3. 重新计算哈希: 使用 用户刚刚输入的明文密码 ,加上 从数据库哈希里提取出来的那个特定的盐 ,按照 提取出来的迭代次数 ,再跑一遍 phpass 哈希算法。
  4. 比较结果: 把新计算出来的哈希结果,和数据库里存储的那个原始哈希字符串进行比较。如果完全一致,密码就验证通过了。

看到没?验证过程的关键在于拿到数据库里存的那个哈希,然后用它包含的信息来校验用户新输入的密码。我们不需要、也通常无法(因为不知道原始的盐)在 Python 里独立生成一个和数据库里一模一样的哈希值。我们只需要能用 Python 实现上面第 3 步和第 4 步的验证逻辑就行了。

Python (FastAPI) 对接 WordPress 登录的解决方案

知道了原理,我们就有办法在 Python 里搞定了。下面是几种推荐的方法:

方案一:在 Python 中模拟 phpass 验证 (使用 passlib)

这是最直接的方法,利用 passlib 这个强大的 Python 库来处理各种密码哈希格式,其中就包括 phpass

原理:

passlib.hash.phpass 模块提供了 PhPassPasswordHasher 类,它可以理解 WordPress 使用的 phpass 格式。我们不用去生成哈希,而是用它的 verify() 方法,传入用户输入的明文密码和从 WordPress 数据库读出来的哈希值,让它帮忙判断是否匹配。

步骤与代码示例:

  1. 安装 passlib:

    pip install passlib
    
  2. FastAPI 示例代码:

    from fastapi import FastAPI, HTTPException, Depends, status
    from pydantic import BaseModel
    import mysql.connector # 或者 psycopg2 (PostgreSQL), pymssql (MSSQL) 等,根据你的 WordPress 数据库类型
    from passlib.hash import phpass
    import os
    from dotenv import load_dotenv
    
    load_dotenv() # 加载环境变量,推荐将数据库凭证等敏感信息放在 .env 文件
    
    app = FastAPI()
    
    # --- 数据库连接配置 ---
    # 强烈建议从环境变量或配置文件读取,避免硬编码
    DB_CONFIG = {
        'user': os.getenv('WP_DB_USER'),
        'password': os.getenv('WP_DB_PASSWORD'),
        'host': os.getenv('WP_DB_HOST'),
        'database': os.getenv('WP_DB_NAME'),
        'raise_on_warnings': True
    }
    WP_TABLE_PREFIX = os.getenv('WP_TABLE_PREFIX', 'wp_') # 获取 WordPress 表前缀,默认为 'wp_'
    
    # --- 数据库连接管理 (简单示例,生产环境建议使用连接池) ---
    def get_db_connection():
        try:
            conn = mysql.connector.connect(**DB_CONFIG)
            yield conn # 使用 yield 使其成为 FastAPI 的 Dpeendency
        except mysql.connector.Error as err:
            print(f"数据库连接错误: {err}")
            raise HTTPException(status_code=500, detail="内部服务器错误 - 数据库连接失败")
        finally:
            if 'conn' in locals() and conn.is_connected():
                conn.close()
    
    # --- 请求体模型 ---
    class UserLogin(BaseModel):
        username: str
        password: str
    
    # --- 密码验证器 ---
    # 创建一个 phpass 哈希器实例
    # 注意: identify=True 让它能识别 phpass 格式
    #       无法直接指定 rounds,因为验证时是根据存储的 hash 来确定 rounds
    hasher = phpass.using(rounds=8, ident="$P
    from fastapi import FastAPI, HTTPException, Depends, status
    from pydantic import BaseModel
    import mysql.connector # 或者 psycopg2 (PostgreSQL), pymssql (MSSQL) 等,根据你的 WordPress 数据库类型
    from passlib.hash import phpass
    import os
    from dotenv import load_dotenv
    
    load_dotenv() # 加载环境变量,推荐将数据库凭证等敏感信息放在 .env 文件
    
    app = FastAPI()
    
    # --- 数据库连接配置 ---
    # 强烈建议从环境变量或配置文件读取,避免硬编码
    DB_CONFIG = {
        'user': os.getenv('WP_DB_USER'),
        'password': os.getenv('WP_DB_PASSWORD'),
        'host': os.getenv('WP_DB_HOST'),
        'database': os.getenv('WP_DB_NAME'),
        'raise_on_warnings': True
    }
    WP_TABLE_PREFIX = os.getenv('WP_TABLE_PREFIX', 'wp_') # 获取 WordPress 表前缀,默认为 'wp_'
    
    # --- 数据库连接管理 (简单示例,生产环境建议使用连接池) ---
    def get_db_connection():
        try:
            conn = mysql.connector.connect(**DB_CONFIG)
            yield conn # 使用 yield 使其成为 FastAPI 的 Dpeendency
        except mysql.connector.Error as err:
            print(f"数据库连接错误: {err}")
            raise HTTPException(status_code=500, detail="内部服务器错误 - 数据库连接失败")
        finally:
            if 'conn' in locals() and conn.is_connected():
                conn.close()
    
    # --- 请求体模型 ---
    class UserLogin(BaseModel):
        username: str
        password: str
    
    # --- 密码验证器 ---
    # 创建一个 phpass 哈希器实例
    # 注意: identify=True 让它能识别 phpass 格式
    #       无法直接指定 rounds,因为验证时是根据存储的 hash 来确定 rounds
    hasher = phpass.using(rounds=8, ident="$P$") # $P$ 是 WordPress 默认标识符, rounds 默认是8
    
    # --- 登录接口 ---
    @app.post("/login/wordpress")
    async def login_wordpress_user(login_data: UserLogin, db_conn = Depends(get_db_connection)):
        """
        验证 WordPress 用户名和密码
        """
        username = login_data.username
        plain_password = login_data.password
    
        cursor = db_conn.cursor(dictionary=True) # 使用字典游标方便获取列名
    
        try:
            # 注意表名可能包含前缀
            query = f"SELECT user_pass FROM {WP_TABLE_PREFIX}users WHERE user_login = %s"
            cursor.execute(query, (username,))
            user_record = cursor.fetchone()
    
            if not user_record:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="用户名或密码错误",
                    headers={"WWW-Authenticate": "Bearer"}, # 可以按需调整
                )
    
            stored_hash = user_record['user_pass'] # 从数据库获取存储的哈希
    
            # 核心验证步骤:使用 passlib 验证
            # verify 会自动从 stored_hash 中提取 salt 和 rounds
            is_valid = hasher.verify(plain_password, stored_hash)
    
            if not is_valid:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="用户名或密码错误",
                    headers={"WWW-Authenticate": "Bearer"},
                )
    
            # 验证成功!
            # 这里可以生成 JWT token,或者记录登录状态等
            # return {"message": "登录成功", "username": username}
            # 实际应用中,应该返回一个 token
            # token = create_access_token(data={"sub": username}) # 假设你有创建 token 的函数
            # return {"access_token": token, "token_type": "bearer"}
    
            return {"message": f"用户 {username} 登录成功!"} # 简化返回
    
    
        except mysql.connector.Error as err:
            print(f"数据库查询错误: {err}")
            raise HTTPException(status_code=500, detail="内部服务器错误 - 查询失败")
        finally:
            cursor.close()
    
    # (可以添加其他 FastAPI 相关代码, 比如启动命令 uvicorn main:app --reload)
    
    
    quot;
    ) # $P$ 是 WordPress 默认标识符, rounds 默认是8 # --- 登录接口 --- @app.post("/login/wordpress") async def login_wordpress_user(login_data: UserLogin, db_conn = Depends(get_db_connection)): """ 验证 WordPress 用户名和密码 """ username = login_data.username plain_password = login_data.password cursor = db_conn.cursor(dictionary=True) # 使用字典游标方便获取列名 try: # 注意表名可能包含前缀 query = f"SELECT user_pass FROM {WP_TABLE_PREFIX}users WHERE user_login = %s" cursor.execute(query, (username,)) user_record = cursor.fetchone() if not user_record: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="用户名或密码错误", headers={"WWW-Authenticate": "Bearer"}, # 可以按需调整 ) stored_hash = user_record['user_pass'] # 从数据库获取存储的哈希 # 核心验证步骤:使用 passlib 验证 # verify 会自动从 stored_hash 中提取 salt 和 rounds is_valid = hasher.verify(plain_password, stored_hash) if not is_valid: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="用户名或密码错误", headers={"WWW-Authenticate": "Bearer"}, ) # 验证成功! # 这里可以生成 JWT token,或者记录登录状态等 # return {"message": "登录成功", "username": username} # 实际应用中,应该返回一个 token # token = create_access_token(data={"sub": username}) # 假设你有创建 token 的函数 # return {"access_token": token, "token_type": "bearer"} return {"message": f"用户 {username} 登录成功!"} # 简化返回 except mysql.connector.Error as err: print(f"数据库查询错误: {err}") raise HTTPException(status_code=500, detail="内部服务器错误 - 查询失败") finally: cursor.close() # (可以添加其他 FastAPI 相关代码, 比如启动命令 uvicorn main:app --reload)

说明:

  • 你需要安装对应的数据库驱动 (mysql-connector-python, psycopg2-binary, pymssql 等)。
  • 代码里用了 python-dotenv.env 文件加载数据库凭证,这是个好习惯。你的 .env 文件大致是这样:
    WP_DB_USER=your_db_user
    WP_DB_PASSWORD=your_db_password
    WP_DB_HOST=localhost
    WP_DB_NAME=your_wordpress_db
    WP_TABLE_PREFIX=wp_ # 如果你修改过,用你实际的前缀
    
  • 直接查询 WordPress 数据库需要你的 API 服务器能够访问 WordPress 的数据库。确保网络连接和防火墙设置允许。
  • hasher.verify(plain_password, stored_hash) 是关键,它完成了密码校验。
  • 成功登录后,你应该生成一个凭证(比如 JWT Token)返回给客户端,后续客户端的请求就带上这个 Token 来证明身份,而不是每次都传用户名密码。

安全建议:

  • 数据库凭证管理: 绝对不要硬编码在代码里。使用环境变量、.env 文件或更专业的秘密管理工具(如 HashiCorp Vault, AWS Secrets Manager 等)。
  • 数据库访问权限: 给 API 使用的数据库用户授予最小必要权限,通常只需要对 wp_users 表的读取权限就够了。
  • 网络安全: 确保 API 服务器和数据库服务器之间的连接是安全的,考虑使用 TLS/SSL 加密连接。API 本身必须使用 HTTPS。
  • 输入验证: 对用户输入的用户名进行适当的清理和验证,防止 SQL 注入(虽然使用了参数化查询能很大程度避免,但仍需注意)。
  • 日志记录: 记录登录尝试(成功和失败),但不要记录明文密码。记录 IP 地址、时间戳有助于监控异常活动。

进阶使用技巧:

  • 数据库连接池: 对于高并发场景,每次请求都创建和关闭数据库连接开销较大。可以使用连接池(如 SQLAlchemy 的连接池、DBUtils 等)来复用连接,提升性能。
  • 异步数据库操作: 如果你的应用并发量非常大,可以考虑使用异步数据库驱动(如 aiomysql, asyncpg)配合 FastAPI 的 async def,避免阻塞事件循环。

方案二:使用 WordPress REST API 和 Application Passwords (推荐)

这个方法不直接碰触数据库和密码哈希细节,而是利用 WordPress 内置的功能,更优雅也更安全。

原理:

WordPress 允许用户在后台为应用程序生成专用的 "Application Passwords"。你的 Python API 可以使用这个 Application Password,通过 WordPress 的 REST API 来验证用户身份。认证过程完全由 WordPress 自己处理。

步骤与代码示例:

  1. 用户在 WordPress 中生成 Application Password:

    • 登录 WordPress 后台。
    • 进入 "用户" (Users) -> "个人资料" (Profile)。
    • 向下滚动找到 "Application Passwords" 部分。
    • 输入一个应用程序名称(比如 "我的移动 App"),点击 "添加新的应用程序密码"。
    • WordPress 会生成一个密码(例如 xxxx xxxx xxxx xxxx xxxx xxxx),这个密码只显示一次,需要立即复制保存好 。它不能找回,忘了只能重新生成一个。
    • 用户需要把他的 WordPress 用户名 和这个 Application Password 提供给你的 Python API(或者在你的移动 App 里输入)。
  2. Python (FastAPI) 使用 Application Password 调用 WP REST API:

    import requests
    from fastapi import FastAPI, HTTPException, status
    from pydantic import BaseModel
    
    app = FastAPI()
    
    # --- 请求体模型 ---
    class UserLoginWPAppPass(BaseModel):
        username: str        # WordPress 用户名
        app_password: str    # 用户生成的 Application Password
    
    # --- WordPress 网站 URL ---
    # 建议从配置或环境变量读取
    WP_SITE_URL = "https://your-wordpress-site.com" # 替换成你的 WordPress 网址
    
    @app.post("/login/wordpress-rest")
    async def login_via_wp_rest(login_data: UserLoginWPAppPass):
        """
        使用 Application Password 通过 WP REST API 验证用户
        """
        username = login_data.username
        app_password = login_data.app_password
    
        # 目标是 WP REST API 的一个需要认证的端点,比如 /wp-json/wp/v2/users/me
        # 这个端点会返回当前认证用户的信息
        rest_api_url = f"{WP_SITE_URL}/wp-json/wp/v2/users/me?context=edit" # context=edit 确保需要认证
    
        try:
            # 使用 Basic Authentication,用户名是 WP 用户名,密码是 Application Password
            response = requests.get(
                rest_api_url,
                auth=(username, app_password),
                timeout=10 # 设置超时
            )
    
            # 检查响应状态码
            if response.status_code == 200:
                # 认证成功!WordPress 认识这个用户和 Application Password
                user_data = response.json() # 可以获取到用户信息
                # 同样,这里应该生成你自己的 API Token (JWT) 返回给客户端
                # token = create_access_token(data={"sub": username, "wp_user_id": user_data.get('id')})
                # return {"access_token": token, "token_type": "bearer"}
                return {"message": f"用户 {user_data.get('name', username)} 通过 REST API 登录成功!"}
            elif response.status_code == 401:
                # 认证失败
                 raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="无效的用户名或 Application Password",
                    headers={"WWW-Authenticate": "Bearer"},
                )
            else:
                # 其他错误 (比如 WP 站点问题, REST API 禁用等)
                # 记录错误详情 response.text
                print(f"WP REST API 请求失败: {response.status_code} - {response.text}")
                raise HTTPException(
                    status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                    detail="无法连接到 WordPress 或验证服务出错",
                )
    
        except requests.exceptions.RequestException as e:
            print(f"请求 WordPress REST API 时出错: {e}")
            raise HTTPException(
                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                detail="连接 WordPress 服务失败",
            )
    
    

说明:

  • 需要安装 requests 库:pip install requests
  • 这种方法不需要直接连接 WordPress 数据库。
  • 你的 API 服务器只需要能通过 HTTP/HTTPS 访问 WordPress 网站即可。
  • 认证逻辑交给了 WordPress,更符合其设计。
  • /wp-json/wp/v2/users/me 是一个常用的测试认证的端点。请求成功会返回当前认证用户的信息。
  • 身份验证是通过 HTTP Basic Authentication 实现的,用户名就是 WordPress 用户名,密码就是用户生成的那个 Application Password。

安全建议:

  • 必须使用 HTTPS: Application Password 相当于一个长期有效的密码,如果在 HTTP 下传输会被轻易截获。确保你的 WordPress 站点和你的 API 都强制使用 HTTPS。
  • Application Password 的保管: 指导用户像保管普通密码一样保管好 Application Password。
  • 权限问题: Application Password 默认拥有该用户的全部权限。如果能配合某些权限管理插件限制 Application Password 能调用的 REST API 端点会更安全,但 WordPress 核心目前对此支持有限。
  • 撤销权限: 用户可以在 WordPress 后台随时撤销某个 Application Password 的授权,这很方便管理。

进阶使用技巧:

  • 错误处理: 更细致地处理各种 HTTP 错误码(403 Forbidden, 500 Internal Server Error 等)。
  • API 发现: 可以先请求 WordPress 站点的 /wp-json/ 端点,查看 REST API 是否启用以及可用的命名空间和路由。
  • 自定义端点: 你可以在 WordPress 中创建自定义的 REST API 端点来处理特定的登录逻辑或返回定制化的用户信息。

方案三:使用 WordPress 认证插件 (如 JWT 插件)

如果 Application Passwords 的 Basic Auth 不满足你的需求(比如你想用更流行的 Token 机制),可以考虑安装 WordPress 的认证插件。

原理:

这类插件(例如 "JWT Authentication for WP REST API")会在 WordPress 中提供新的 REST API 端点。你的 Python API 向这些端点发送用户名和密码,插件验证后会返回一个有时效性的 Token (通常是 JWT - JSON Web Token)。之后你的 Python API 或客户端 App 在访问需要保护的资源时,只需在请求头里带上这个 Token 即可。

步骤与代码示例 (以 JWT 插件为例):

  1. 在 WordPress 安装和配置 JWT 插件:

    • 安装并启用 "JWT Authentication for WP REST API" 插件 (或其他类似插件)。
    • 按照插件文档,通常需要在 wp-config.php 文件中定义一个 JWT_AUTH_SECRET_KEY这个密钥必须非常安全,随机生成且保密
    • 可能还需要配置 CORS (跨域资源共享) 如果你的 FastAPI 和 WordPress 不在同一个域下。插件通常有相关设置。
  2. Python (FastAPI) 获取 JWT Token:

    import requests
    from fastapi import FastAPI, HTTPException, status
    from pydantic import BaseModel
    
    app = FastAPI()
    
    # --- 请求体模型 ---
    class UserLoginWP(BaseModel):
        username: str
        password: str
    
    # --- WordPress 网站 URL 和 JWT Token 端点 ---
    WP_SITE_URL = "https://your-wordpress-site.com" # 替换
    JWT_TOKEN_ENDPOINT = f"{WP_SITE_URL}/wp-json/jwt-auth/v1/token" # 插件提供的获取 Token 的 URL
    
    @app.post("/login/wordpress-jwt")
    async def get_wp_jwt_token(login_data: UserLoginWP):
        """
        向 WordPress JWT 插件请求 Token
        """
        try:
            response = requests.post(
                JWT_TOKEN_ENDPOINT,
                data={ # 通常是 form-data 或 json,看插件要求
                    'username': login_data.username,
                    'password': login_data.password,
                },
                timeout=10
            )
    
            if response.status_code == 200:
                # 获取 Token 成功
                token_data = response.json()
                # token_data 可能包含 token, user_email, user_nicename, user_display_name 等
                # 你可以直接把这个 WP 发的 token 透传给客户端,
                # 或者用它验证用户身份后,再生成你自己 API 的 token
                # return {"wp_token_data": token_data} # 直接透传示例
                # 或者生成你自己的 token
                # my_token = create_access_token(data={"sub": login_data.username, "wp_data": token_data})
                # return {"access_token": my_token, "token_type": "bearer"}
    
                return {"message": "获取 WordPress JWT Token 成功", "data": token_data} # 简化返回
    
            elif response.status_code == 403: # 常见错误码是 403 Forbidden
                 raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED, # 转换为 401 更符合 API 语境
                    detail="用户名或密码错误 (来自 JWT 插件)",
                    headers={"WWW-Authenticate": "Bearer"},
                )
            else:
                print(f"请求 WP JWT Token 失败: {response.status_code} - {response.text}")
                # 这里可能包含插件没配置好、CORS 问题等
                raise HTTPException(
                    status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                    detail="WordPress JWT 认证服务出错",
                )
    
        except requests.exceptions.RequestException as e:
            print(f"请求 WordPress JWT Token 时出错: {e}")
            raise HTTPException(
                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                detail="连接 WordPress 服务失败",
            )
    
    # --- 使用 Token 访问受保护的 WP 资源 (示例) ---
    # 这个逻辑通常在你的客户端或者需要访问 WP 数据的 API 端点中实现
    # def access_wp_resource_with_token(token: str):
    #     headers = {'Authorization': f'Bearer {token}'}
    #     protected_url = f"{WP_SITE_URL}/wp-json/wp/v2/posts" # 例子:获取文章
    #     try:
    #         response = requests.get(protected_url, headers=headers, timeout=10)
    #         response.raise_for_status() # 检查 HTTP 错误
    #         return response.json()
    #     except requests.exceptions.RequestException as e:
    #         print(f"访问受保护资源失败: {e}")
    #         return None
    
    

说明:

  • 需要 requests 库。
  • 你需要知道插件提供的获取 Token 的确切 URL(通常在插件文档里有)。
  • 获取 Token 通常是 POST 请求,需要发送用户名和密码。
  • 拿到 Token 后,后续访问需要该插件保护的 WordPress REST API 端点时,需要在 HTTP 请求的 Authorization Header 里带上 Bearer <token>

安全建议:

  • 强密钥: JWT_AUTH_SECRET_KEY 必须非常强壮和保密,泄露它会导致严重安全问题。
  • HTTPS 强制: 所有通信,包括获取 Token 和使用 Token,都必须在 HTTPS 下进行。
  • Token 时效性: 配置合理的 Token 过期时间。太短影响用户体验,太长增加风险。考虑实现 Token 刷新机制。
  • 插件安全: 依赖第三方插件意味着你需要信任该插件的安全性,并及时更新它以修复可能出现的漏洞。
  • Token 存储: 客户端(比如移动 App)需要安全地存储获取到的 Token。

进阶使用技巧:

  • Token 结构 (Claims): 理解 JWT Token 包含哪些信息(Claims),比如用户 ID、用户名、过期时间等,可以在你的 API 中利用这些信息。
  • Token 刷新: 实现 Token 刷新逻辑,让用户在 Token 过期前可以无缝地获取新 Token,提升体验。
  • 服务端验证 Token: 如果你的 FastAPI 需要验证来自客户端的 WordPress JWT Token,你需要使用配置在 WordPress 中的那个 JWT_AUTH_SECRET_KEY 在 Python 端进行解密和验证签名(使用如 PyJWT 库)。

再说说 wp-config.php 里的 KEY 和 SALT

最后再强调一下,wp-config.php 里的 AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY 和对应的 SALT 主要用于:

  • 增强 WordPress 登录 Cookie 的安全性,让它们更难被猜测和伪造。
  • 生成和验证 Nonces (Number used once),防止跨站请求伪造 (CSRF) 攻击。

它们不直接参与 用户密码存储时使用的 phpass 哈希过程。phpass 使用的是每个密码独有的、嵌入在哈希值本身里的盐。所以,尝试用这些 wp-config.php 的常量去配置 passlib.phpass 是不对的,也是徒劳的。

希望上面这几种方案能帮你打通 Python API 和 WordPress 的用户登录!选择哪种方案取决于你的具体需求、对系统复杂度的接受程度以及安全考量。通常来说,方案二 (Application Passwords) 是对许多场景来说,是推荐的最简单、集成度较好的方式。如果需要更灵活的 Token 机制,可以考虑方案三 (JWT 插件)方案一 (直接数据库验证) 虽然可行,但耦合度较高,需要更关注数据库安全和维护。