workerman 本身不支持 ssl 双向认证,因其 ssl_context 仅加载服务端证书,未暴露 cafile、client_ca 等必需参数及客户端证书获取接口;推荐用 nginx 终结 tls 并透传证书信息至 workerman。

Workerman 本身不支持 SSL 双向认证(Client Certificate Auth) —— 它的 ssl_context 仅处理服务端证书加载,没有提供验证客户端证书的接口或回调。硬要实现双向认证,必须绕过 Workerman 的 SSL 层,改用底层 OpenSSL 手动控制握手,或交由反向代理(如 Nginx)完成。
为什么 Workerman 的 ssl_context 不能做双向认证
Workerman 的 SSL 支持基于 PHP 的 stream_socket_server 和 OpenSSL 上下文,但只透传了有限字段(如 local_cert、local_pk、verify_peer)。它不暴露 verify_peer_name、cafile、capath、client_ca 或 verify_depth 等双向认证必需参数,也无法在握手后读取客户端证书信息(如 SSL_get_peer_certificate 对应的 PHP 接口不存在)。
常见误操作包括:
- 在
ssl_context里加'cafile' => '/path/to/ca.crt'—— Workerman 忽略该字段,启动无报错但实际无效 - 设
'verify_peer' => true并以为这就启用了双向认证 —— 实际只是让 OpenSSL 尝试校验服务端证书(而 Workerman 自己又不提供服务端证书链完整性检查),对客户端证书完全不碰 - 试图在
$connection->onSslHandshake回调里取客户端证书 —— 这个回调根本不存在,Workerman 没有暴露该钩子
替代方案:用 Nginx 做 TLS 终结 + 透传客户端证书信息
这是最稳定、可落地的方案。Nginx 负责完成完整的 TLS 握手和客户端证书校验,再以明文(或自定义头)把证书信息转发给 Workerman。
实操要点:
- Nginx 配置中启用
ssl_client_certificate和ssl_verify_client on,指向你的 CA 根证书文件 - 用
proxy_set_header X-Client-Cert $ssl_client_cert把 Base64 编码的客户端证书透传到后端(注意长度限制,建议只传 DN 或指纹) - Workerman 接收 HTTP 请求时,从
$_SERVER['HTTP_X_CLIENT_CERT']或类似头里提取并解析(可用openssl_x509_parse()) - 确保 Nginx 的
proxy_pass指向 Workerman 的http://或websocket://地址,而非https://—— 否则会形成双重加密失败
示例 Nginx 片段:
location /wss {
proxy_pass http://127.0.0.1:2346;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_set_header X-Client-Verify $ssl_client_verify;
}
极端情况:自己用 PHP socket + OpenSSL 手写双向 TLS 服务
如果你必须在 Workerman 进程内完成双向认证,且无法引入 Nginx,唯一路径是放弃 Worker 类,直接用 stream_socket_server 创建监听,并手动管理 SSL 上下文和握手流程。
关键限制:
- 无法复用 Workerman 的连接池、心跳、定时器等高级功能
- 需自行解析 TLS 握手包、调用
stream_socket_enable_crypto()多次、处理SSL_ERROR_WANT_READ/WRITE - 客户端证书信息需通过
stream_context_get_options($socket)['ssl']['peer_certificate']获取(PHP 8.0+),且仅在握手完成后才可用 - Workerman 的事件循环(
EventLoop)与原生 stream 不兼容,需换用libevent或ev扩展重写主循环
这已脱离“配置 Workerman”的范畴,属于从零实现一个 TLS WebSocket 服务器 —— 工程成本远高于加一层 Nginx。
真正需要双向认证的场景(如金融、政企系统),几乎都采用反向代理终结 TLS 的方式。Workerman 的定位是高性能应用层协议服务器,不是 TLS 协议栈。强行在它里面补全双向认证,就像给自行车加涡轮增压——能装,但轮子早飞了。











