来自AI助手的总结
在WordPress站点中,通过创建一个PHP服务器与C++客户端实现用户密码验证,保障数据库安全和用户信息的正确性。
方案:
在WordPress站点(后文简称:WP站点),如果想使用C++进行用户的验证的话,需要去复原加密算法,才能尝试去匹配数据库中的密码哈希值。
在6.8版本后的WP,密码加密算法被更新了,所以博主设计了一下方案:
思路:
使用TCP协议,创建一个PHP Server,数据交互使用JSON进行。PHP Server来负责验证用户,且端口可以不对外开放,保证了安全。
C++部分,同样也使用TCP协议。但是作为客户端,将数据铭文转发到PHP Server即可。再将PHP Server回送的数据解析就行。
实现:
PHP:
#!/usr/bin/env php
<?php
/**
* WordPress 密码验证 TCP 服务器
* 用法: php wp_auth_server.php [port] [wordpress_path]
* 示例: php wp_auth_server.php 9001 /www/wwwroot/wordpress
*/
set_time_limit(0);
error_reporting(E_ERROR);
ini_set('display_errors', 'stderr');
// 配置
$port = $argv[1] ?? 9001;
$wp_path = $argv[2] ?? findWordPress();
$bind_address = '0.0.0.0';
if (!$wp_path || !file_exists($wp_path . '/wp-load.php')) {
die("错误: 无法找到 WordPress 目录,请指定路径\n用法: php {$argv[0]} [port] [/path/to/wordpress]\n");
}
echo "正在启动 WordPress 密码验证服务器...\n";
echo "WordPress 路径: $wp_path\n";
echo "监听地址: $bind_address:$port\n";
// 加载 WordPress(不加载主题,加速启动)
define('WP_USE_THEMES', false);
require_once $wp_path . '/wp-load.php';
echo "WordPress 加载完成 (版本: " . get_bloginfo('version') . ")\n";
// 创建 socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$socket) {
die("Socket 创建失败: " . socket_strerror(socket_last_error()) . "\n");
}
// 允许地址重用
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
// 绑定地址
if (!socket_bind($socket, $bind_address, $port)) {
die("绑定失败: " . socket_strerror(socket_last_error($socket)) . "\n");
}
// 监听
if (!socket_listen($socket, 10)) {
die("监听失败: " . socket_strerror(socket_last_error($socket)) . "\n");
}
echo "服务器已启动,等待连接...\n";
// 信号处理(优雅关闭)
if (function_exists('pcntl_signal')) {
pcntl_signal(SIGTERM, function() use ($socket) {
echo "\n收到关闭信号,正在停止...\n";
socket_close($socket);
exit(0);
});
pcntl_signal(SIGINT, function() use ($socket) {
echo "\n收到中断信号,正在停止...\n";
socket_close($socket);
exit(0);
});
}
// 查找 WordPress 的辅助函数
function findWordPress() {
$current = getcwd();
// 向上查找 5 层目录
for ($i = 0; $i < 5; $i++) {
if (file_exists($current . '/wp-load.php')) {
return $current;
}
if (file_exists($current . '/wordpress/wp-load.php')) {
return $current . '/wordpress';
}
if (file_exists($current . '/www/wwwroot/wordpress/wp-load.php')) {
return $current . '/www/wwwroot/wordpress';
}
$current = dirname($current);
}
return null;
}
// 验证用户
function verifyUser($username, $password) {
$user = get_user_by('login', $username);
if (!$user) {
$user = get_user_by('email', $username);
}
if (!$user) {
return ['success' => false, 'error' => '用户不存在'];
}
// 使用 WordPress 的验证函数(自动处理 $wp$ 前缀)
$valid = wp_check_password($password, $user->user_pass, $user->ID);
if ($valid) {
return [
'success' => true,
'user_id' => $user->ID,
'user_login' => $user->user_login,
'user_email' => $user->user_email,
'display_name' => $user->display_name
];
} else {
return ['success' => false, 'error' => '密码错误'];
}
}
// 主循环
while (true) {
// 处理信号(如果可用)
if (function_exists('pcntl_signal_dispatch')) {
pcntl_signal_dispatch();
}
// 接受连接
$client = socket_accept($socket);
if (!$client) {
continue;
}
// 读取数据
$input = '';
while ($buf = socket_read($client, 2048, PHP_NORMAL_READ)) {
$input .= $buf;
if (strpos($input, "\n") !== false) break;
}
$input = trim($input);
if (empty($input)) {
socket_write($client, json_encode(['error' => '空请求']) . "\n");
socket_close($client);
continue;
}
// 解析 JSON
$request = json_decode($input, true);
if (!$request || !isset($request['action'])) {
$response = ['error' => '无效请求格式'];
} else {
// 处理请求
switch ($request['action']) {
case 'verify':
if (empty($request['username']) || empty($request['password'])) {
$response = ['success' => false, 'error' => '缺少用户名或密码'];
} else {
$response = verifyUser($request['username'], $request['password']);
}
break;
case 'ping':
$response = ['status' => 'ok', 'wordpress_version' => get_bloginfo('version')];
break;
default:
$response = ['error' => '未知操作: ' . $request['action']];
}
}
// 发送响应
$output = json_encode($response) . "\n";
socket_write($client, $output);
socket_close($client);
}
socket_close($socket);
c++:
头文件:
#pragma once
/*
# 使用
- 先获取一个实例指针
- 启动WPAuthClient(startWPAuthClient客户端)
- 停止客户端调用:stopWPAuthClient()函数
- 验证用户必须使用账户名验证,参数参阅实现的.Cpp文件
*/
#include "../../nlohmann/json.hpp"
#include "../../log4cpp/log4mini.h"
#include <iostream>
#include <string>
#include <cstring>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <future>
#include <atomic>
#include <utility>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
class WPAuthClient {
public:
// 获取单例
static WPAuthClient* getInstance(const std::string& host = "127.0.0.1", int port = 9001);
// 启动WPAuth客户端
void startWPAuthClient();
// 停止WPAuth客户端
void stopWPAuthClient();
// 验证用户与密码
bool verifyUserPassword(const std::string& username, const std::string& password, nlohmann::json& userInfo);
private:
// 构造函数
WPAuthClient() = default;
WPAuthClient(const std::string& host, int port);
// 析构函数
~WPAuthClient();
// 禁用拷贝
WPAuthClient(const WPAuthClient&) = delete;
WPAuthClient& operator=(const WPAuthClient&) = delete;
// 工作循环
void workerLoop();
// 确保连接
bool ensureConnected();
// 验证执行
nlohmann::json doVerify(const nlohmann::json& request);
private:
static WPAuthClient* instance_; // 获取实例
static std::mutex instance_mutex_; // 实例锁
std::string m_host; // 主机地址
int m_port; // 监听端口
int m_sock; // socket
std::mutex m_sock_mutex; // 保护 socket 操作
std::thread m_worker_thread; // 工作线程
std::queue<std::pair<nlohmann::json, std::promise<nlohmann::json> > > m_task_queue; // 任务队列
std::mutex m_queue_mutex; // 队列锁,保护队列
std::condition_variable m_cv; // 条件变量
std::atomic<bool> m_is_running{false}; // 原子类型,判断线程是否在运行
};
源文件:
#include "WPAuth.h"
// 静态成员定义
WPAuthClient* WPAuthClient::instance_ = nullptr;
std::mutex WPAuthClient::instance_mutex_;
/*
============================================================================
Function: getInstance
Description: 获取WPAuthClient单例
Parameters:
- std::string: 主机信息
- int: 监听地址
Return: 返回一个WPAuthClient指针
============================================================================
*/
WPAuthClient* WPAuthClient::getInstance(const std::string& host, int port)
{
if (instance_ == nullptr)
{
std::lock_guard<std::mutex> lock(instance_mutex_);
if (instance_ == nullptr)
{
instance_ = new WPAuthClient(host, port);
}
}
return instance_;
}
/*
============================================================================
Function: startWPAuthClient
Description: 启动WPAuth客户端
Parameters:
- 无参数: 无释义
Return: 无返回值
============================================================================
*/
void WPAuthClient::startWPAuthClient()
{
if(this->m_is_running)
{
Log4Warn("WPAuthClient is already running");
return;
}
// 设置运行状态
this->m_is_running = true;
this->m_worker_thread = std::thread(&WPAuthClient::workerLoop, this);
return;
}
/*
============================================================================
Function: stopWPAuthClient
Description: 停止WPAuth客户端
Parameters:
- 无参数: 无释义
Return: 无返回值
============================================================================
*/
void WPAuthClient::stopWPAuthClient()
{
if(this->m_is_running)
{
this->m_is_running = false;
this->m_cv.notify_all();
if (this->m_worker_thread.joinable())
{
this->m_worker_thread.join();
}
if (this->m_sock >= 0)
{
close(this->m_sock);
this->m_sock = -1;
}
}
}
/*
============================================================================
Function: verifyUserPassword
Description: 验证用户密码
Parameters:
- const std::string&: 一个字符串,用户名
- const std::string&: 一个字符串,用户密码明文
- nlohmann::json&: 作为返回值使用,记录错误信息或者是用户信息
Return: 用户密码正确返回true,否则返回false,且参数三用于记录验证的详细信息
============================================================================
*/
bool WPAuthClient::verifyUserPassword(const std::string& username, const std::string& password, nlohmann::json& userInfo)
{
nlohmann::json request = {
{"action", "verify"},
{"username", username},
{"password", password}
};
// 创建 promise-future 用于获取异步结果
std::promise<nlohmann::json> promise;
std::future<nlohmann::json> future = promise.get_future();
{
std::lock_guard<std::mutex> lock(this->m_queue_mutex);
this->m_task_queue.emplace(request, std::move(promise));
}
// 唤醒工作线程
this->m_cv.notify_one();
// 等待结果(超时10s)
if (future.wait_for(std::chrono::seconds(10)) == std::future_status::timeout)
{
return false;
}
nlohmann::json response = future.get();
userInfo = response;
if (response.value("success", false))
{
return true;
}
return false;
}
/*
============================================================================
Function: PAuthClient
Description: 构造函数
Parameters:
- const std::string&: 一个字符串,主机地址
- int: 监听端口
Return: 无返回值
============================================================================
*/
WPAuthClient::WPAuthClient(const std::string& host, int port) :
m_host(host),
m_port(port),
m_sock(-1)
{
}
/*
============================================================================
Function: ~WPAuthClient
Description: 析构函数
Parameters:
- 无参数: 无释义
Return: 无返回值
============================================================================
*/
WPAuthClient::~WPAuthClient()
{
WPAuthClient::stopWPAuthClient();
}
/*
============================================================================
Function: workerLoop
Description: 工作循环
Parameters:
- 无参数: 无释义
Return: 无返回值
============================================================================
*/
void WPAuthClient::workerLoop()
{
while (this->m_is_running)
{
std::unique_lock<std::mutex> lock(this->m_queue_mutex);
// 等待任务队列非空
this->m_cv.wait(lock, [this] {
return !this->m_task_queue.empty() || !this->m_is_running;
});
if (!this->m_is_running)
break;
std::pair<nlohmann::json, std::promise<nlohmann::json> > task = std::move(this->m_task_queue.front());
this->m_task_queue.pop();
lock.unlock();
// 执行验证
nlohmann::json result = doVerify(task.first);
task.second.set_value(result);
}
}
/*
============================================================================
Function: ensureConnected
Description: 确认是否已经连接验证服务器
Parameters:
- 无参数: 无释义
Return: 连接状态返回true,否则返回false
============================================================================
*/
bool WPAuthClient::ensureConnected()
{
std::lock_guard<std::mutex> lock(this->m_sock_mutex);
if (this->m_sock >= 0)
return true; // 已连接
// 创建监听套接字
this->m_sock = socket(AF_INET, SOCK_STREAM, 0);
if (this->m_sock < 0)
return false;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(this->m_port);
inet_pton(AF_INET, this->m_host.c_str(), &addr.sin_addr);
// 设置连接超时
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
setsockopt(this->m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
if (connect(this->m_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
// 连接失败关闭套接字
close(this->m_sock);
this->m_sock = -1;
return false;
}
// 设置发送/接收超时
tv.tv_sec = 5;
setsockopt(this->m_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
return true;
}
/*
============================================================================
Function: doVerify
Description: 验证执行器 - 发送请求到验证服务器并解析JSON
Parameters:
- const nlohmann::json&: 一个用于请求的json
Return: 返回一个nlohmann::json,验证的内容
============================================================================
*/
nlohmann::json WPAuthClient::doVerify(const nlohmann::json& request)
{
if (!ensureConnected())
{
return std::move(nlohmann::json({
{"success", false},
{"error", "Unable to connect to the authentication server"}
}));
}
std::string req_str = request.dump() + "\n";
{
std::lock_guard<std::mutex> lock(this->m_sock_mutex);
if (send(this->m_sock, req_str.c_str(), req_str.length(), 0) < 0)
{
// 发送失败,标记连接断开,下次重连
close(this->m_sock);
this->m_sock = -1;
return std::move(nlohmann::json({
{"success", false},
{"error", "Sending failed, connection has been disconnected"}
}));
}
}
// 接收响应
char buffer[8192];
memset(buffer, 0, sizeof(buffer));
int bytes = recv(this->m_sock, buffer, sizeof(buffer) - 1, 0);
if (bytes <= 0)
{
std::lock_guard<std::mutex> lock(this->m_sock_mutex);
close(this->m_sock);
this->m_sock = -1;
return std::move(nlohmann::json({
{"success", false},
{"error", "接收失败或超时"}
}));
}
try
{
// 关闭连接,下次需要再连接
{
std::lock_guard<std::mutex> lock(this->m_sock_mutex);
close(this->m_sock);
this->m_sock = -1;
}
// 解析json
return nlohmann::json::parse(std::string(buffer, bytes));
}
catch (const std::exception& e)
{
return std::move(nlohmann::json({
{"success", false},
{"error", std::string("JSON parsing failed: ") + e.what()}
}));
}
return std::move(nlohmann::json({
{"success", false},
{"error", std::string("unknown state")}
}));
}
代码解析:
C++:
持续验证请求的完整执行流程:
假设主线程不断调用 verifyUserPassword(),工作线程在循环处理:
时刻 T0: 启动
├─ 主线程:调用 startWPAuthClient()
└─ 工作线程:启动,进入 workerLoop()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
时刻 T1: 第1次验证请求到达
├─ 主线程:
│ ├─ 创建 request = {"action": "verify", "username": "ta01", "password": "Wsz123456."}
│ ├─ 创建 promise p1
│ ├─ 创建 future f1 = p1.get_future()
│ ├─ 加锁 m_queue_mutex
│ │ └─ m_task_queue.emplace(request, std::move(p1)) ← p1 所有权转移到队列
│ ├─ 解锁 m_queue_mutex
│ ├─ m_cv.notify_one() ← 唤醒工作线程
│ └─ f1.wait_for(10s) ← 主线程阻塞在这里,等待结果
│
└─ 工作线程:
├─ 在 m_cv.wait() 被唤醒
├─ 加锁 m_queue_mutex
├─ 检查队列:不为空 ✓
├─ task = m_task_queue.front() ← 取出 (request, p1)
├─ m_task_queue.pop()
├─ 解锁 m_queue_mutex
├─ 执行:result = doVerify(request)
│ ├─ ensureConnected() → 创建新 socket,连接 PHP 服务器
│ ├─ send(request) → 发送 JSON
│ ├─ recv(buffer) → 接收 JSON
│ └─ parse JSON → 返回结果
│
├─ task.second.set_value(result) ← 承诺兑现!
│ └─ f1 被激活(从 wait_for 返回)
│
└─ 回到 while 循环开始,继续等待下一个任务
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
时刻 T2: 工作线程刚兑现承诺,主线程收到结果
├─ 主线程:
│ ├─ future.get() 返回 result
│ ├─ 检查 result["success"] 是否为 true
│ └─ 返回 true/false
│
└─ 工作线程:
└─ 继续循环,进入 m_cv.wait() 睡眠状态
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
时刻 T3: 第2次验证请求到达(比如 ta001)
├─ 主线程:
│ ├─ 创建 promise p2
│ ├─ 创建 future f2
│ ├─ 加锁 m_queue_mutex
│ │ └─ m_task_queue.emplace(request2, std::move(p2))
│ ├─ 解锁 m_queue_mutex
│ ├─ m_cv.notify_one() ← 唤醒工作线程
│ └─ f2.wait_for(10s) ← 主线程再次阻塞
│
└─ 工作线程:
├─ 再次被唤醒
├─ 取出 (request2, p2)
├─ 执行:result2 = doVerify(request2)
│ ├─ ensureConnected()
│ │ ├─ 检查 m_sock >= 0?
│ │ ├─ 如果还是第一次的 socket → 假设已关闭 → 返回 false ❌
│ │ │ 或者
│ │ ├─ 创建新 socket → 连接 PHP 服务器
│ │ └─ 返回 true ✓
│ ├─ send(request2)
│ ├─ recv(buffer)
│ └─ parse JSON
│
└─ task.second.set_value(result2) ← p2 兑现
(重复 T3 的流程...)
核心数据结构
// 任务队列的定义(在 .h 文件)
std::queue<std::pair<nlohmann::json, std::promise<nlohmann::json>>> m_task_queue;
↑ ↑
请求 承诺对象
队列中存储的内容:
┌─────────────────────────────────┐
│ 任务队列 (m_task_queue) │
├─────────────────────────────────┤
│ [0] (request1, promise1) │ ← 等待被处理
│ [1] (request2, promise2) │ ← 等待被处理
│ [2] (request3, promise3) │ ← 等待被处理
└─────────────────────────────────┘
线程同步机制:
主线程 工作线程
│ │
├─ 创建 promise ──────────┐ │
│ └──→ 存入队列
│ │
├─ notify_one() ────────────→ 唤醒 ← m_cv.wait()
│ │
├─ future.wait_for(10s) ← ┐ │
│ (阻塞) └─── set_value(result)
│ │
└─ 继续执行 继续循环
© 版权声明
THE END










暂无评论内容