【问题标题】:Laravel Broadcasting - Private Channels Accessible Without Bearer TokenLaravel 广播 - 无需承载令牌即可访问的私人频道
【发布时间】:2020-07-14 12:03:37
【问题描述】:

我已经设置了带有 laravel-echo 的 socket.io 来加入并收听 laravel 广播频道。公共频道运行良好,因为它们不需要任何身份验证。私人频道没有按预期工作,我可以使用 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-Echo-Server 配置

{
"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-Echo-Server

[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 laravel-5 socket.io laravel-passport laravel-broadcast


    【解决方案1】:

    好的,这很有趣。我决定检查 laravel-echo-server 如何请求“广播/身份验证”以及它如何处理该请求的响应。

    你可以看看这里:https://github.com/tlaverdure/laravel-echo-server/blob/master/src/channels/private-channel.ts

    所以laravel-echo-server如果broadcasting/auth的响应码是200就返回true,如果响应码不是200或者请求出错就返回false。

    这里的问题是,当你向 laravel api route 发送一个由护照身份验证处理的请求时,它确实返回“未验证”消息但没有 401 代码,因此 laravel-echo-server 认为请求成功并允许用户加入频道。

    解决方案:

    1. 返回 401 代码和 Passport 未经身份验证的响应
    2. 通道认证中间件

    返回 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",
    

    结果

    1. 未经身份验证的 401 - (Laravel-Echo-Server False) 开启:[来自客户端的请求中不存在令牌,请求的用户频道!== 正在请求用户的频道]

    2. Authenticated 200 - (Laravel-Echo-Server True) On : [令牌存在于来自客户端的请求和请求的用户频道 == 请求用户的频道]

    您可以将验证用户身份的逻辑应用到中间件中的通道。

    【讨论】:

    • 问题是 $user = Auth::User();不管用。我没有得到任何数据
    猜你喜欢
    • 2018-03-03
    • 2021-11-15
    • 2021-07-15
    • 2023-03-17
    • 2018-02-23
    • 2021-06-01
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多