您希望在用户通过默认的 WordPress 登录表单登录后,生成一个包含 JWT(JSON Web Token)的 HTTP-only cookie。这是一种增强 WordPress 安全性的好方法,因为 HTTP-only cookie 不能被 JavaScript 访问,可以防止 XSS 攻击窃取认证信息。
要实现这个功能,您需要:
- 在用户成功登录后生成 JWT
- 将 JWT 设置为 HTTP-only cookie
- 在需要验证用户身份的地方验证这个 JWT
实现方案
WordPress 没有内置的 JWT 支持,所以您需要自己实现或使用插件。以下是一个自定义实现的方法:
1. 添加必要的 JWT 库
首先,您需要一个 PHP JWT 库。可以使用 Composer 安装 firebase/php-jwt
:
composer require firebase/php-jwt
2. 监听登录成功事件并生成 JWT
WordPress 有一个 wp_login
钩子,当用户成功登录时会触发。您可以使用这个钩子来生成 JWT 并设置为 cookie:
add_action('wp_login', 'set_jwt_auth_cookie', 10, 2);
function set_jwt_auth_cookie($user_login, $user) {
// 引入 JWT 库
require_once __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
// 设置密钥(应该存储在安全的地方,比如 wp-config.php)
$secret_key = defined('JWT_AUTH_SECRET_KEY') ? JWT_AUTH_SECRET_KEY : 'your-secret-key';
// 设置 token 有效期(例如 12 小时)
$issued_at = time();
$expiration = $issued_at + (60 * 60 * 12);
// 准备 token 数据
$token_data = array(
'iss' => get_site_url(),
'iat' => $issued_at,
'exp' => $expiration,
'user' => array(
'id' => $user->ID,
'email' => $user->user_email,
'roles' => $user->roles
)
);
// 生成 JWT
$token = JWT::encode($token_data, $secret_key, 'HS256');
// 设置 HTTP-only cookie
setcookie(
'wp_jwt_token',
$token,
[
'expires' => $expiration,
'path' => '/',
'domain' => parse_url(get_site_url(), PHP_URL_HOST),
'secure' => is_ssl(),
'httponly' => true,
'samesite' => 'Strict'
]
);
}
3. 验证 JWT
您可以创建一个函数来验证 JWT:
function verify_jwt_token() {
// 如果用户已经通过 WordPress 标准方式登录,不需要验证 JWT
if (is_user_logged_in()) {
return true;
}
// 检查 JWT cookie 是否存在
if (!isset($_COOKIE['wp_jwt_token'])) {
return false;
}
require_once __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$token = $_COOKIE['wp_jwt_token'];
$secret_key = defined('JWT_AUTH_SECRET_KEY') ? JWT_AUTH_SECRET_KEY : 'your-secret-key';
try {
// 解码并验证 token
$decoded = JWT::decode($token, new Key($secret_key, 'HS256'));
// 检查 token 是否过期
if ($decoded->exp < time()) {
return false;
}
// 如果需要,可以在这里设置当前用户
$user_id = $decoded->user->id;
wp_set_current_user($user_id);
return true;
} catch (Exception $e) {
return false;
}
}
4. 与 REST API 集成
如果您需要在 REST API 中使用 JWT 认证,可以添加一个过滤器:
add_filter('rest_authentication_errors', 'jwt_authenticate_rest_api', 10, 1);
function jwt_authenticate_rest_api($errors) {
// 如果已经通过其他方式认证,不干扰
if ($errors !== null) {
return $errors;
}
// 验证 JWT
if (verify_jwt_token()) {
return true;
}
// JWT 验证失败,返回错误
return new WP_Error(
'jwt_auth_failed',
__('JWT 认证失败'),
array('status' => 401)
);
}
5. 在 wp-config.php 中设置密钥
为了安全起见,应该在 wp-config.php
中定义 JWT 密钥:
define('JWT_AUTH_SECRET_KEY', 'your-unique-secret-key-here');
建议使用 WordPress 的密钥生成 API 来生成一个强密钥:https://api.wordpress.org/secret-key/1.1/salt/
6. 处理登出
当用户登出时,您应该清除 JWT cookie:
add_action('wp_logout', 'clear_jwt_auth_cookie');
function clear_jwt_auth_cookie() {
setcookie(
'wp_jwt_token',
'',
[
'expires' => time() - 3600,
'path' => '/',
'domain' => parse_url(get_site_url(), PHP_URL_HOST),
'secure' => is_ssl(),
'httponly' => true,
'samesite' => 'Strict'
]
);
}
完整实现示例
将以上代码整合到一个插件中:
<?php
/**
* Plugin Name: WordPress JWT Authentication
* Description: 为 WordPress 添加 JWT 认证支持
* Version: 1.0
* Author: Your Name
*/
// 确保直接访问时退出
if (!defined('ABSPATH')) {
exit;
}
// 引入 JWT 库
require_once __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// 登录成功后设置 JWT cookie
add_action('wp_login', 'set_jwt_auth_cookie', 10, 2);
function set_jwt_auth_cookie($user_login, $user) {
// 设置密钥
$secret_key = defined('JWT_AUTH_SECRET_KEY') ? JWT_AUTH_SECRET_KEY : 'your-secret-key';
// 设置 token 有效期(例如 12 小时)
$issued_at = time();
$expiration = $issued_at + (60 * 60 * 12);
// 准备 token 数据
$token_data = array(
'iss' => get_site_url(),
'iat' => $issued_at,
'exp' => $expiration,
'user' => array(
'id' => $user->ID,
'email' => $user->user_email,
'roles' => $user->roles
)
);
// 生成 JWT
$token = JWT::encode($token_data, $secret_key, 'HS256');
// 设置 HTTP-only cookie
setcookie(
'wp_jwt_token',
$token,
[
'expires' => $expiration,
'path' => '/',
'domain' => parse_url(get_site_url(), PHP_URL_HOST),
'secure' => is_ssl(),
'httponly' => true,
'samesite' => 'Strict'
]
);
}
// 验证 JWT
function verify_jwt_token() {
// 如果用户已经通过 WordPress 标准方式登录,不需要验证 JWT
if (is_user_logged_in()) {
return true;
}
// 检查 JWT cookie 是否存在
if (!isset($_COOKIE['wp_jwt_token'])) {
return false;
}
$token = $_COOKIE['wp_jwt_token'];
$secret_key = defined('JWT_AUTH_SECRET_KEY') ? JWT_AUTH_SECRET_KEY : 'your-secret-key';
try {
// 解码并验证 token
$decoded = JWT::decode($token, new Key($secret_key, 'HS256'));
// 检查 token 是否过期
if ($decoded->exp < time()) {
return false;
}
// 设置当前用户
$user_id = $decoded->user->id;
wp_set_current_user($user_id);
return true;
} catch (Exception $e) {
return false;
}
}
// 与 REST API 集成
add_filter('rest_authentication_errors', 'jwt_authenticate_rest_api', 10, 1);
function jwt_authenticate_rest_api($errors) {
// 如果已经通过其他方式认证,不干扰
if ($errors !== null) {
return $errors;
}
// 验证 JWT
if (verify_jwt_token()) {
return true;
}
// JWT 验证失败,返回错误
return new WP_Error(
'jwt_auth_failed',
__('JWT 认证失败'),
array('status' => 401)
);
}
// 处理登出
add_action('wp_logout', 'clear_jwt_auth_cookie');
function clear_jwt_auth_cookie() {
setcookie(
'wp_jwt_token',
'',
[
'expires' => time() - 3600,
'path' => '/',
'domain' => parse_url(get_site_url(), PHP_URL_HOST),
'secure' => is_ssl(),
'httponly' => true,
'samesite' => 'Strict'
]
);
}
安全注意事项
- 确保使用强密钥并保持其安全
- 设置合理的 token 过期时间
- 使用 HTTPS 保护 cookie 传输
- 使用 HTTP-only 和 Secure 标志保护 cookie
- 考虑实现 token 刷新机制以延长会话
现有插件选项
如果您不想自己实现,可以考虑使用现有的插件:
- JWT Authentication for WP REST API
- Simple JWT Authentication
- WP REST API - JWT Authentication
这些插件提供了类似的功能,可能更容易集成到您的项目中。
Notes
在提供的代码片段中,我没有看到与 JWT 或 HTTP-only cookie 直接相关的代码。WordPress 核心没有内置 JWT 支持,所以需要自定义实现或使用第三方插件。上述解决方案基于 WordPress 的钩子系统和 PHP 的 cookie 功能,结合第三方 JWT 库来实现所需功能。