本文目录导读:

在 PHP WebSocket 中进行权限验证,主要有以下几种常见方案:
Token 验证方案(推荐)
客户端连接时携带 Token
// 客户端连接 WebSocket 时
const ws = new WebSocket('ws://example.com:8080?token=YOUR_AUTH_TOKEN');
服务端验证
<?php
// WebSocket 服务端代码(使用 Workerman 或 Ratchet)
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class ChatServer implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
// 获取 Token
$queryParams = [];
parse_str(parse_url($conn->httpRequest->getUri(), PHP_URL_QUERY), $queryParams);
$token = $queryParams['token'] ?? '';
// 验证 Token
if (!$this->validateToken($token)) {
$conn->close();
return;
}
// 将用户信息绑定到连接
$conn->user_id = $this->getUserIdFromToken($token);
$conn->token = $token;
$this->clients->attach($conn);
echo "新连接: {$conn->resourceId}\n";
}
private function validateToken($token) {
// 从数据库或缓存中验证 Token
// 示例:Redis 或 JWT 验证
if (empty($token)) {
return false;
}
// JWT 验证示例
try {
$decoded = JWT::decode($token, JWT_SECRET, ['HS256']);
return true;
} catch (\Exception $e) {
return false;
}
}
private function getUserFromToken($token) {
// 通过 Token 获取用户信息
return JWT::decode($token, JWT_SECRET, ['HS256']);
}
}
基于 Redis 的 Session 验证
<?php
class WebSocketAuth {
public function authenticate(ConnectionInterface $conn) {
$sessionId = $this->getSessionId($conn);
// 从 Redis 获取 Session 数据
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$sessionData = $redis->get("PHPREDIS_SESSION:$sessionId");
if (!$sessionData) {
return false;
}
// 解析 Session 数据
$userData = session_decode($sessionData);
if (!isset($userData['user_id'])) {
return false;
}
$conn->user_id = $userData['user_id'];
return true;
}
private function getSessionId($conn) {
// 从请求中获取 Session ID
$headers = $conn->httpRequest->getHeaders();
$cookieHeader = $headers['Cookie'][0] ?? '';
preg_match('/PHPSESSID=([^;]+)/', $cookieHeader, $matches);
return $matches[1] ?? '';
}
}
双向认证方案
<?php
class AuthWebSocketServer implements MessageComponentInterface {
public function onOpen(ConnectionInterface $conn) {
// 初始状态:未认证
$conn->authenticated = false;
// 收到认证请求后
$conn->send(json_encode([
'type' => 'auth_required'
]));
}
public function onMessage(ConnectionInterface $from, $msg) {
$data = json_decode($msg, true);
// 检查是否是认证请求
if (!$from->authenticated) {
$this->handleAuth($from, $data);
return;
}
// 已认证的连接处理正常消息
$this->handleMessage($from, $data);
}
private function handleAuth(ConnectionInterface $conn, $data) {
if ($data['type'] === 'authenticate') {
$token = $data['token'] ?? '';
// 验证 Token
if ($this->validateToken($token)) {
$conn->authenticated = true;
$conn->user = $this->getUser($token);
$conn->send(json_encode([
'type' => 'authenticated',
'data' => ['user' => $conn->user]
]));
} else {
$conn->send(json_encode([
'type' => 'auth_failed',
'message' => 'Invalid token'
]));
$conn->close();
}
}
}
}
客户端 JavaScript 实现
// 客户端认证
class WebSocketClient {
constructor(token) {
this.token = token;
this.connected = false;
this.initWebSocket();
}
initWebSocket() {
this.ws = new WebSocket('ws://localhost:8080');
this.ws.onopen = () => {
console.log('正在建立 WebSocket 连接...');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'auth_required') {
// 发送认证请求
this.authenticate();
} else if (data.type === 'authenticated') {
this.connected = true;
console.log('WebSocket 认证成功');
this.onAuthenticated(data.data);
} else if (data.type === 'auth_failed') {
console.error('WebSocket 认证失败');
this.onAuthFailed(data.message);
} else {
// 处理正常消息
this.handleMessage(data);
}
};
this.ws.onerror = (error) => {
console.error('WebSocket 错误:', error);
};
this.ws.onclose = () => {
console.log('WebSocket 连接关闭');
this.connected = false;
this.reconnect();
};
}
authenticate() {
this.ws.send(JSON.stringify({
type: 'authenticate',
token: this.token
}));
}
send(data) {
if (this.connected) {
this.ws.send(JSON.stringify(data));
} else {
console.error('WebSocket 未认证');
}
}
reconnect() {
// 重连逻辑
setTimeout(() => {
this.initWebSocket();
}, 3000);
}
}
// 使用
const client = new WebSocketClient('your_jwt_token');
权限控制完整示例
<?php
class SecureWebSocketServer implements MessageComponentInterface {
private $clients;
public function onOpen(ConnectionInterface $conn) {
$this->clients[$conn->resourceId] = $conn;
$conn->permissions = [];
}
public function onMessage(ConnectionInterface $from, $msg) {
$data = json_decode($msg, true);
// 权限检查
if (!$this->checkPermission($from, $data['action'] ?? '')) {
$from->send(json_encode([
'type' => 'error',
'message' => '权限不足'
]));
return;
}
// 处理消息
$this->processMessage($from, $data);
}
private function checkPermission($conn, $action) {
// 获取用户权限列表
$permissions = $this->getUserPermissions($conn->user_id);
// 检查动作权限
switch ($action) {
case 'send_message':
return in_array('send_message', $permissions);
case 'delete_message':
return in_array('admin', $permissions);
default:
return false;
}
}
private function getUserPermissions($userId) {
// 从数据库或缓存获取权限
return ['send_message', 'read_messages']; // 示例
}
}
最佳实践建议
-
使用 JWT 进行身份验证:
- 简单、安全、无状态
- 可以包含用户信息和过期时间
-
连接超时机制:
// 设置认证超时 $conn->authTimeout = time() + 10; // 10秒内必须完成认证
// 定期检查 if (time() > $conn->authTimeout && !$conn->authenticated) { $conn->close(); }
3. **使用 HTTPS/WSS**:
```php
// SSL 配置
$server = new Ratchet\App('localhost', 8080, '0.0.0.0');
$server->route('/chat', new ChatServer(), ['*']);
- 日志记录:
// 记录认证信息 error_log("User {$userId} authenticated at " . date('Y-m-d H:i:s'));
这些方案可以根据你的具体需求进行选择和组合,确保 WebSocket 连接的安全性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播