Python/FastAPI 验证 WordPress 密码 (含 phpass 方案)
2025-04-23 06:25:32
搞定 Python FastAPI 与 WordPress 用户登录:密码 Hashing 对接指南
你在用 Python (特别是 FastAPI) 构建一个 API,想让你的 WordPress 网站用户也能通过这个 API 登录,比如从移动 App 登录?这想法挺酷!但你可能马上就碰到了钉子:WordPress 的密码怎么在 Python 里进行校验?用 passlib.phpass
好像有点眉目,但对着 wp-config.php
里一堆 KEY
和 SALT
常量,还是不知道怎么下手。
别急,这确实是个常见的坑。这篇文章就带你弄明白 WordPress 密码验证这回事,并给出几种在 Python API 里实现对接的方法。
WordPress 密码 Hashing 的小麻烦
如果你直接看 WordPress 数据库里的 wp_users
表,你会发现 user_pass
字段里的密码字符串长得有点怪,通常类似 $P$Bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
这样。
这玩意儿不是简单的 MD5 或者 SHA1。WordPress 使用的是一个叫做 phpass
(Portable PHP Password Hashing Framework) 的库来处理密码。它的特点是:
- 迭代哈希 (Iterative Hashing): 它不是只哈希一次,而是进行多轮哈希计算,增加破解难度。
- 加盐 (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()
):
- 获取存储的哈希: 根据用户名,从数据库
wp_users
表里读出user_pass
字段的值,也就是那个$P$B...
字符串。 - 提取信息: 从这个存储的哈希字符串中,
phpass
能够解析出当初使用的 盐 (salt) 和 迭代次数 (iteration count) 。这些信息就嵌在哈希值里面。 - 重新计算哈希: 使用 用户刚刚输入的明文密码 ,加上 从数据库哈希里提取出来的那个特定的盐 ,按照 提取出来的迭代次数 ,再跑一遍
phpass
哈希算法。 - 比较结果: 把新计算出来的哈希结果,和数据库里存储的那个原始哈希字符串进行比较。如果完全一致,密码就验证通过了。
看到没?验证过程的关键在于拿到数据库里存的那个哈希,然后用它包含的信息来校验用户新输入的密码。我们不需要、也通常无法(因为不知道原始的盐)在 Python 里独立生成一个和数据库里一模一样的哈希值。我们只需要能用 Python 实现上面第 3 步和第 4 步的验证逻辑就行了。
Python (FastAPI) 对接 WordPress 登录的解决方案
知道了原理,我们就有办法在 Python 里搞定了。下面是几种推荐的方法:
方案一:在 Python 中模拟 phpass
验证 (使用 passlib
)
这是最直接的方法,利用 passlib
这个强大的 Python 库来处理各种密码哈希格式,其中就包括 phpass
。
原理:
passlib.hash.phpass
模块提供了 PhPassPasswordHasher
类,它可以理解 WordPress 使用的 phpass
格式。我们不用去生成哈希,而是用它的 verify()
方法,传入用户输入的明文密码和从 WordPress 数据库读出来的哈希值,让它帮忙判断是否匹配。
步骤与代码示例:
-
安装
passlib
:pip install passlib
-
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
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)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)
说明:
- 你需要安装对应的数据库驱动 (
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 自己处理。
步骤与代码示例:
-
用户在 WordPress 中生成 Application Password:
- 登录 WordPress 后台。
- 进入 "用户" (Users) -> "个人资料" (Profile)。
- 向下滚动找到 "Application Passwords" 部分。
- 输入一个应用程序名称(比如 "我的移动 App"),点击 "添加新的应用程序密码"。
- WordPress 会生成一个密码(例如
xxxx xxxx xxxx xxxx xxxx xxxx
),这个密码只显示一次,需要立即复制保存好 。它不能找回,忘了只能重新生成一个。 - 用户需要把他的 WordPress 用户名 和这个 Application Password 提供给你的 Python API(或者在你的移动 App 里输入)。
-
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 插件为例):
-
在 WordPress 安装和配置 JWT 插件:
- 安装并启用 "JWT Authentication for WP REST API" 插件 (或其他类似插件)。
- 按照插件文档,通常需要在
wp-config.php
文件中定义一个JWT_AUTH_SECRET_KEY
。这个密钥必须非常安全,随机生成且保密 。 - 可能还需要配置 CORS (跨域资源共享) 如果你的 FastAPI 和 WordPress 不在同一个域下。插件通常有相关设置。
-
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 插件) 。方案一 (直接数据库验证) 虽然可行,但耦合度较高,需要更关注数据库安全和维护。