本文目录导读:

在 Laravel 中,广播频道授权验证是通过频道类和授权回调来控制的,以下是完整的实现方案:
基础频道授权
在 routes/channels.php 中定义
<?php
use App\Models\User;
use App\Models\Order;
use Illuminate\Support\Facades\Broadcast;
// 用户私有频道
Broadcast::channel('user.{userId}', function (User $user, $userId) {
return (int) $user->id === (int) $userId;
});
// 订单频道 - 只有订单相关用户才能监听
Broadcast::channel('order.{orderId}', function (User $user, $orderId) {
$order = Order::find($orderId);
if (!$order) {
return false;
}
// 检查用户是否为订单的创建者或管理员
return $user->id === $order->user_id || $user->isAdmin();
});
// 团队频道
Broadcast::channel('team.{teamId}', function (User $user, $teamId) {
return $user->teams()->where('teams.id', $teamId)->exists();
});
使用 Channel 类(推荐)
创建频道类
php artisan make:channel OrderChannel
定义频道类 app/Broadcasting/OrderChannel.php
<?php
namespace App\Broadcasting;
use App\Models\Order;
use App\Models\User;
class OrderChannel
{
/**
* 创建新的频道实例
*/
public function __construct()
{
//
}
/**
* 验证用户是否可以监听该频道
*/
public function join(User $user, $orderId)
{
$order = Order::findOrFail($orderId);
// 业务逻辑验证
return $user->id === $order->user_id
|| $user->isAdmin()
|| $order->assigned_to === $user->id;
}
}
在 routes/channels.php 中注册
Broadcast::channel('order.{orderId}', \App\Broadcasting\OrderChannel::class);
前端授权配置
Laravel Echo 配置
// resources/js/bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true,
// 自定义授权端点
authEndpoint: '/broadcasting/auth',
// 自定义授权头(如果需要)
auth: {
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
}
});
自定义授权逻辑
自定义授权中间件
// app/Http/Middleware/EnsureTokenIsValid.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class EnsureTokenIsValid
{
public function handle(Request $request, Closure $next)
{
// 验证 token
if (!$request->hasHeader('Authorization')) {
return response('Unauthorized', 401);
}
$token = str_replace('Bearer ', '', $request->header('Authorization'));
// 验证 token 逻辑...
return $next($request);
}
}
在 routes/channels.php 中使用中间件
Broadcast::routes(['middleware' => ['auth:api', 'EnsureTokenIsValid']]);
高级授权场景
多条件授权
Broadcast::channel('chat.{roomId}', function (User $user, $roomId) {
$room = ChatRoom::findOrFail($roomId);
// 多种授权条件
$isMember = $room->members()->where('user_id', $user->id)->exists();
$isPublic = $room->is_public;
$isModerator = $user->isModeratorOf($room);
// 返回 true 表示允许访问,也可以返回数组包含用户信息
if ($isMember || $isPublic || $isModerator) {
return ['id' => $user->id, 'name' => $user->name];
}
return false;
});
动态权限检查
Broadcast::channel('notifications.{userId}', function (User $user, $userId) {
// 检查用户是否订阅了通知
$subscription = NotificationSubscription::where([
'user_id' => $userId,
'subscriber_id' => $user->id
])->first();
return $subscription !== null;
});
测试授权
编写授权测试
// tests/Feature/BroadcastAuthTest.php
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Models\Order;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class BroadcastAuthTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function user_can_authenticate_to_private_channel()
{
$user = User::factory()->create();
$order = Order::factory()->create(['user_id' => $user->id]);
$this->actingAs($user)
->post('/broadcasting/auth', [
'channel_name' => 'private-order.' . $order->id,
'socket_id' => '123456.789012'
])
->assertSuccessful();
}
/** @test */
public function unauthorized_user_cannot_access_channel()
{
$user = User::factory()->create();
$otherUser = User::factory()->create();
$order = Order::factory()->create(['user_id' => $otherUser->id]);
$this->actingAs($user)
->post('/broadcasting/auth', [
'channel_name' => 'private-order.' . $order->id,
'socket_id' => '123456.789012'
])
->assertForbidden();
}
}
最佳实践
安全建议
// 1. 始终验证用户身份
Broadcast::channel('secure.{id}', function (User $user, $id) {
// 不要信任前端传来的 ID,从认证用户获取
return $user->id === (int) $id;
});
// 2. 使用资源所有者的 ID
Broadcast::channel('resources.{resourceId}', function (User $user, $resourceId) {
$resource = Resource::findOrFail($resourceId);
// 检查用户是否是资源所有者
return $resource->owner_id === $user->id;
});
// 3. 实现精细的权限控制
Broadcast::channel('projects.{projectId}', function (User $user, $projectId) {
return $user->hasPermission('view-project', $projectId);
});
性能优化
// 缓存授权结果
Broadcast::channel('data.{tenantId}', function (User $user, $tenantId) {
return Cache::remember("channel-auth-{$user->id}-{$tenantId}", 60, function () use ($user, $tenantId) {
return $user->tenants()->where('id', $tenantId)->exists();
});
});
常见问题解决
跨域问题
// config/broadcasting.php
'connections' => [
'pusher' => [
// ...
'options' => [
'cluster' => 'mt1',
'useTLS' => true,
'curl_options' => [
CURLOPT_SSL_VERIFYPEER => false,
],
],
],
],
自定义认证响应
// 在 AppServiceProvider 中
use Illuminate\Support\Facades\Broadcast;
Broadcast::auth(function ($request) {
// 自定义认证逻辑
return [
'user' => $request->user()->only(['id', 'name', 'email'])
];
});
通过以上实现,你可以确保只有经过授权的用户才能监听到相应的广播频道,保障应用的安全性。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播