/wp-json/wp/v2/users 和 /wp-json/wp/v2/users/me 都需要登录验证后才能访问,/wp-json/wp/v2/users 正常,但是 /wp-json/wp/v2/users/me 不正常,User ID 为 0,但是通过以下代码又是能拿到 ID 的。
add_filter('rest_authentication_errors', function($result) {
// 调试会话信息
echo ('is_user_logged_in: ' . (is_user_logged_in() ? 'true' : 'false'));
echo('Cookies: ' . print_r($_COOKIE, true));
echo('Current User: ' . (wp_get_current_user()->ID ?: 'None'));
if (!is_user_logged_in()) {
return new WP_Error('rest_not_logged_in', 'You are not logged in.', ['status' => 401]);
}
$current_user_id = get_current_user_id();
echo ('Current User ID: ' . $current_user_id);
return $result;
});
解密,这里的 rest_cookie_check_errors 函数会在请求 REST 接口时验证 _wpnonce
,如果没有提交这个字段,那么无法访问当前用户信息,而其他接口不需要访问 currrent_user。
#0 C:\www\test_006\wordpress\wp-includes\rest-api.php(1128): wp_set_current_user()
#1 C:\www\test_006\wordpress\wp-includes\class-wp-hook.php(324): rest_cookie_check_errors()
#2 C:\www\test_006\wordpress\wp-includes\plugin.php(205): apply_filters()
#3 C:\www\test_006\wordpress\wp-includes\rest-api\class-wp-rest-server.php(197): apply_filters()
#4 C:\www\test_006\wordpress\wp-includes\rest-api\class-wp-rest-server.php(436): check_authentication()
#5 C:\www\test_006\wordpress\wp-includes\rest-api.php(459): serve_request()
#6 C:\www\test_006\wordpress\wp-includes\class-wp-hook.php(324): rest_api_loaded()
#7 C:\www\test_006\wordpress\wp-includes\class-wp-hook.php(348): apply_filters()
#8 C:\www\test_006\wordpress\wp-includes\plugin.php(565): do_action()
#9 C:\www\test_006\wordpress\wp-includes\class-wp.php(418): do_action_ref_array()
#10 C:\www\test_006\wordpress\wp-includes\class-wp.php(818): parse_request()
#11 C:\www\test_006\wordpress\wp-includes\functions.php(1342): main()
#12 C:\www\test_006\wordpress\wp-blog-header.php(16): wp()
#13 C:\www\test_006\wordpress\index.php(17): require()
function rest_cookie_check_errors( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
global $wp_rest_auth_cookie;
/*
* Is cookie authentication being used? (If we get an auth
* error, but we're still logged in, another authentication
* must have been used).
*/
if ( true !== $wp_rest_auth_cookie && is_user_logged_in() ) {
return $result;
}
// Determine if there is a nonce.
$nonce = null;
if ( isset( $_REQUEST['_wpnonce'] ) ) {
$nonce = $_REQUEST['_wpnonce'];
} elseif ( isset( $_SERVER['HTTP_X_WP_NONCE'] ) ) {
$nonce = $_SERVER['HTTP_X_WP_NONCE'];
}
if ( null === $nonce ) {
// No nonce at all, so act as if it's an unauthenticated request.
wp_set_current_user( 0 );
return true;
}
// Check the nonce.
$result = wp_verify_nonce( $nonce, 'wp_rest' );
if ( ! $result ) {
add_filter( 'rest_send_nocache_headers', '__return_true', 20 );
return new WP_Error( 'rest_cookie_invalid_nonce', __( 'Cookie check failed' ), array( 'status' => 403 ) );
}
// Send a refreshed nonce in header.
rest_get_server()->send_header( 'X-WP-Nonce', wp_create_nonce( 'wp_rest' ) );
return true;
}
最后解密,如果自己实现了 REST 验证,应该在 rest_authentication_errors 钩子回调中返回 true,来去除 rest_cookie_check_errors 调用。
add_filter( 'rest_authentication_errors', 'my_jwt_authentication_bypass', 5 );
function my_jwt_authentication_bypass( $result ) {
// 如果已经有结果了(如错误),保持它
if ( ! empty( $result ) ) {
return $result;
}
// 检查 JWT(此处仅示意,你需根据自己的逻辑解析 token)
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if ( str_starts_with( $token, 'Bearer ' ) ) {
$jwt = substr( $token, 7 );
$user_id = my_verify_jwt_and_get_user_id( $jwt ); // ← 你自己的解码逻辑
if ( $user_id ) {
wp_set_current_user( $user_id ); // 设置当前用户
return true; // ✅ 验证成功,短路后续验证
}
}
return null; // 继续后续验证
}
总结
- wordpress 的大多数服务端请求都带 determine_current_user 这个钩子验证,这个验证可以自定义验证用户是否登录,当然在自定义之前,用户已经判断过登录 cookie,已经从 cookie 中拿出 userid。 这里要做的是添加 jwt 验证。
- 即使 determine_current_user 做完,如果还想 jwt 认证来保护 wordpress 自带的接口,就需要定义 rest_authentication_errors 钩子回调,并在回调验证通过后返回 true,这样下一步的 NONCE 验证就不会启用。
- 不能简单的任务通过登录 cookie 验证过的登录用户就可以随意请求 REST 接口, wordpress 还有他自己的进一步验证机制,比如 NONCE 验证。