Laravel 广播 - 无需 Bearer Token 即可访问的专用频道
Laravel Broadcasting - Private Channels Accessible Without Bearer Token
我已经设置了 socket.io 和 laravel-echo 来加入和收听 laravel 广播频道。 Public 频道工作正常,因为它们不需要任何身份验证。私人频道未按预期工作,我可以使用 socket.io 客户端加入任何私人频道而无需通过授权令牌。
Socket.io 客户端
window.Echo = new Echo({
host: "http://127.0.0.1:6001",
auth:{
headers: {
Accept: 'application/json',
Authorization: 'Bearer ',
},
},
broadcaster: 'socket.io',
});
window.Echo.private('user'+"."+userid)
.listen('Notification', (e) => {
console.log(e);
})
Laravel-回声服务器配置
{
"authHost": "http://127.0.0.1:8000",
"authEndpoint": "/broadcasting/auth",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {
"port": "6379",
"host": "localhost"
},
"sqlite": {}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"secureOptions": 67108864,
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
},
"apiOriginAllow": {
"allowCors": true,
"allowOrigin": "localhost",
"allowMethods": "GET, POST",
"allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
}
}
频道路由
Broadcast::channel('user.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
BroadcastServiceProvider
Broadcast::routes(['middleware' => ['auth:api']]);
授权配置
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
],
127.0.0.1:8000/broadcasting/auth无令牌访问时响应
{"message":"Unauthenticated."}
Laravel-回声服务器
[4:50:17 PM] - Preparing authentication request to: http://127.0.0.1:8000
[4:50:17 PM] - Sending auth request to: http://127.0.0.1:8000/broadcasting/auth
[4:50:17 PM] - LtnbMInYDGa_QMMcAAAA authenticated for: private-user.1
[4:50:17 PM] - LtnbMInYDGa_QMMcAAAA joined channel: private-user.1
所以我的猜测是 laravel-echo-server 在响应“未验证”时没有返回 false
任何帮助将不胜感激
好的,解决这个问题很有趣。我决定检查 laravel-echo-server 如何请求“broadcasting/auth”以及它如何处理该请求的响应。
你可以在这里看看:https://github.com/tlaverdure/laravel-echo-server/blob/master/src/channels/private-channel.ts
因此,如果 broadcasting/auth 的响应代码为 200,则 laravel-echo-server return 为 true,如果响应代码不是 200 或有一个 returns,则为 false请求错误。
这里的问题是,当您向 laravel api 由护照身份验证处理的路由发送请求时,它会显示 return“未验证”消息,但没有 401 代码,因此laravel-echo-server认为请求成功,允许用户加入频道。
解决方案:
- 返回带有 Passport 未验证响应的 401 代码
- 通道认证中间件
返回 401 代码和 Passport 未验证响应
projectdir\app\Exceptions Handler.php
...
use Illuminate\Auth\AuthenticationException;
...
public function render($request, Exception $exception)
{
if($exception instanceof AuthenticationException){
return response()->json(['message' => $exception->getMessage()], 401);
}else{
return response()->json(['message' => $exception->getMessage() ]);
}
return parent::render($request, $exception);
}
通道认证中间件
php artisan make:middleware [姓名]
projectdir\app\Http\Middleware[姓名].php
use Closure;
use Illuminate\Support\Facades\Auth;
class SocketAuth
{
public function handle($request, Closure $next)
{
$user = Auth::User();
if($user !== null){
if($request->channel_name == "private-user.".$user->id){
return $next($request);
}else{
return response()->json(["message" => "Unauthenticated."], 401);
}
}
return response()->json(["message" => "Unauthenticated."], 401);
}
}
BroadcastServiceProvider
Broadcast::routes(["prefix" => "api", 'middleware' => ['auth:api', 'SocketAuth']]);
注册中间件
projectdir\app\Http Kernel.php
protected $routeMiddleware = [
...
'SocketAuth' => \App\Http\Middleware\SocketAuth::class,
];
Laravel-Echo-Server 配置
"authEndpoint": "/api/broadcasting/auth",
结果
Unauthenticated 401 - (Laravel-Echo-Server False) On : [ No token present in request from client side, Requested user channel !== Requesting user's channel ]
Authenticated 200 - (Laravel-Echo-Server True) On : [ Token present in request from client side and Requested user channel == Requesting user's channel ]
您可以将验证用户的逻辑应用到中间件中的通道。
我已经设置了 socket.io 和 laravel-echo 来加入和收听 laravel 广播频道。 Public 频道工作正常,因为它们不需要任何身份验证。私人频道未按预期工作,我可以使用 socket.io 客户端加入任何私人频道而无需通过授权令牌。
Socket.io 客户端
window.Echo = new Echo({
host: "http://127.0.0.1:6001",
auth:{
headers: {
Accept: 'application/json',
Authorization: 'Bearer ',
},
},
broadcaster: 'socket.io',
});
window.Echo.private('user'+"."+userid)
.listen('Notification', (e) => {
console.log(e);
})
Laravel-回声服务器配置
{
"authHost": "http://127.0.0.1:8000",
"authEndpoint": "/broadcasting/auth",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {
"port": "6379",
"host": "localhost"
},
"sqlite": {}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"secureOptions": 67108864,
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
},
"apiOriginAllow": {
"allowCors": true,
"allowOrigin": "localhost",
"allowMethods": "GET, POST",
"allowHeaders": "Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorization, X-CSRF-TOKEN, X-Socket-Id"
}
}
频道路由
Broadcast::channel('user.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
BroadcastServiceProvider
Broadcast::routes(['middleware' => ['auth:api']]);
授权配置
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
],
127.0.0.1:8000/broadcasting/auth无令牌访问时响应
{"message":"Unauthenticated."}
Laravel-回声服务器
[4:50:17 PM] - Preparing authentication request to: http://127.0.0.1:8000
[4:50:17 PM] - Sending auth request to: http://127.0.0.1:8000/broadcasting/auth
[4:50:17 PM] - LtnbMInYDGa_QMMcAAAA authenticated for: private-user.1
[4:50:17 PM] - LtnbMInYDGa_QMMcAAAA joined channel: private-user.1
所以我的猜测是 laravel-echo-server 在响应“未验证”时没有返回 false
任何帮助将不胜感激
好的,解决这个问题很有趣。我决定检查 laravel-echo-server 如何请求“broadcasting/auth”以及它如何处理该请求的响应。
你可以在这里看看:https://github.com/tlaverdure/laravel-echo-server/blob/master/src/channels/private-channel.ts
因此,如果 broadcasting/auth 的响应代码为 200,则 laravel-echo-server return 为 true,如果响应代码不是 200 或有一个 returns,则为 false请求错误。
这里的问题是,当您向 laravel api 由护照身份验证处理的路由发送请求时,它会显示 return“未验证”消息,但没有 401 代码,因此laravel-echo-server认为请求成功,允许用户加入频道。
解决方案:
- 返回带有 Passport 未验证响应的 401 代码
- 通道认证中间件
返回 401 代码和 Passport 未验证响应
projectdir\app\Exceptions Handler.php
...
use Illuminate\Auth\AuthenticationException;
...
public function render($request, Exception $exception)
{
if($exception instanceof AuthenticationException){
return response()->json(['message' => $exception->getMessage()], 401);
}else{
return response()->json(['message' => $exception->getMessage() ]);
}
return parent::render($request, $exception);
}
通道认证中间件
php artisan make:middleware [姓名]
projectdir\app\Http\Middleware[姓名].php
use Closure;
use Illuminate\Support\Facades\Auth;
class SocketAuth
{
public function handle($request, Closure $next)
{
$user = Auth::User();
if($user !== null){
if($request->channel_name == "private-user.".$user->id){
return $next($request);
}else{
return response()->json(["message" => "Unauthenticated."], 401);
}
}
return response()->json(["message" => "Unauthenticated."], 401);
}
}
BroadcastServiceProvider
Broadcast::routes(["prefix" => "api", 'middleware' => ['auth:api', 'SocketAuth']]);
注册中间件
projectdir\app\Http Kernel.php
protected $routeMiddleware = [
...
'SocketAuth' => \App\Http\Middleware\SocketAuth::class,
];
Laravel-Echo-Server 配置
"authEndpoint": "/api/broadcasting/auth",
结果
Unauthenticated 401 - (Laravel-Echo-Server False) On : [ No token present in request from client side, Requested user channel !== Requesting user's channel ]
Authenticated 200 - (Laravel-Echo-Server True) On : [ Token present in request from client side and Requested user channel == Requesting user's channel ]
您可以将验证用户的逻辑应用到中间件中的通道。