Broadcasting 频道认证与前端接入
High Contrast
Dark Mode
Light Mode
Sepia
Forest
1 min read210 words

Broadcasting 频道认证与前端接入

私有频道和 Presence 频道需要服务器端认证——确保用户只能订阅自己有权限的频道。本节讲清楚认证流程、CORS 处理,以及在不同前端框架中正确配置 Echo。


广播认证流程

graph TD A["前端 Echo\n订阅 private-user.1"] --> B["POST /broadcasting/auth\n带 Cookie 或 Bearer Token"] B --> C["Sanctum 验证身份"] C --> D["routes/channels.php\n检查频道权限"] D --> |允许| E["返回签名 Token"] D --> |拒绝| F["返回 403"] E --> G["WebSocket 握手成功\n开始接收广播"]

广播认证路由配置

// bootstrap/app.php
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
channels: __DIR__.'/../routes/channels.php',   // 必须注册
)
// routes/channels.php
use Illuminate\Support\Facades\Broadcast;
// 私有频道:用户只能订阅自己的通知频道
Broadcast::channel('user.{userId}', function ($user, int $userId) {
return (int) $user->id === $userId;
});
// 私有频道:Sanctum API Token 认证(Bearer Token 方式)
Broadcast::channel('user.{userId}', function ($user, int $userId) {
return (int) $user->id === $userId;
}, ['guards' => ['api', 'sanctum']]);  // 指定认证 Guard
// Presence 频道:返回用户信息(非 true/false)
Broadcast::channel('project.{projectId}', function ($user, int $projectId) {
if ($user->can('view', \App\Models\Project::find($projectId))) {
return ['id' => $user->id, 'name' => $user->name, 'avatar' => $user->avatar_url];
}
return false;
});

Sanctum API Token 的广播认证

默认的 /broadcasting/auth 路由使用 web Guard(Cookie Session)。对于用 Bearer Token 认证的 API 客户端,需要额外配置:

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->api(prepend: [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
]);
})
// 前端:Bearer Token 方式的 Echo 配置
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT,
forceTLS: false,
enabledTransports: ['ws', 'wss'],
// 为广播认证请求添加 Bearer Token
authEndpoint: '/broadcasting/auth',
auth: {
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
Accept: 'application/json',
},
},
});

自定义广播认证端点

// 如果需要自定义认证逻辑,可以创建自定义端点
// routes/api.php
Route::post('/broadcasting/auth', function (Request $request) {
// 自定义认证逻辑
$user = $request->user('sanctum');
if (!$user) {
return response()->json(['error' => 'Unauthenticated'], 401);
}
// 调用 Broadcast 的默认认证
return Broadcast::auth($request);
})->middleware('auth:sanctum');
// Echo 配置指向自定义端点
window.Echo = new Echo({
// ...
authEndpoint: '/api/broadcasting/auth',
});

React 中的完整接入示例

// hooks/useEcho.js
import { useEffect, useRef } from 'react';
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
let echoInstance = null;
export function getEcho(token) {
if (!echoInstance) {
window.Pusher = Pusher;
echoInstance = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: Number(import.meta.env.VITE_REVERB_PORT),
forceTLS: false,
enabledTransports: ['ws', 'wss'],
auth: {
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/json',
},
},
});
}
return echoInstance;
}
// components/TaskList.jsx
export function TaskList({ projectId }) {
const [tasks, setTasks] = useState([]);
const { token } = useAuth();
useEffect(() => {
const echo = getEcho(token);
// 监听项目任务更新
const channel = echo.join(`project.${projectId}`)
.here((members) => console.log('在线成员:', members))
.listen('.task.updated', ({ task }) => {
setTasks(prev => prev.map(t => t.id === task.id ? task : t));
})
.listen('.task.created', ({ task }) => {
setTasks(prev => [task, ...prev]);
});
return () => {
echo.leave(`project.${projectId}`);
};
}, [projectId, token]);
// ...
}

广播调试

# 测试广播(在 tinker 中手动触发事件)
php artisan tinker
>>> event(new \App\Events\TaskCompleted(App\Models\Task::first()))
# 查看广播日志(确认事件是否推送到 Reverb)
# Reverb 会在控制台打印连接和消息日志
php artisan reverb:start --debug
# 检查 Redis 队列(广播默认走 queue:broadcast 队列)
php artisan queue:work --queue=broadcast

下一章RESTful API 设计与 API Resources——事件广播做好了实时性,现在设计规范的 RESTful API——API Resource 层、版本控制、分页规范,让前端对接体验一致。