laravel5.7 + pusher.comで、プライベート・チャネルを実装してみた。
1, 何が違うのかというと、
app/Events/MessageCreated.phpのチャネル指定のメソッドを
Channel(パブリック)から
PrivateChannel(プライベート)へ変更しただけ。
発信側の変更は、これだけ!
1 2 3 4 5 |
public function broadcastOn() { // return new Channel('my-channel'); return new PrivateChannel('my-channel'); } |
pusher.comのDebug Consoleで見てみると、channel名にprivate-というプレフィックスが付与されている。
Channel: private-my-channel, Event: my-event
2, プライベートチャネルには、認証処理が必須!
routes/channels.phpに、各チャネル毎に認証処理を記述する
1 2 3 4 5 |
// プライベートチャネルには、認証処理が必須!プレフィックス(private-)は自動的に付与されるので不要 Broadcast::channel('my-channel', function () { // とりあえず、認証はせずに常にOK return true; }); |
3, 受信側の変更も、チャネル名にprivate-というプレフィックスが付与する。(laravelのプライベートチャネルはログイン状態じゃないと使用できないので、ユーザ認証機能を作らないと使えない)
※private channelは、プレフィックスとしてprivate-が必須!
resources/views/index.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<title>Pusher Test</title> <script src="https://js.pusher.com/4.4/pusher.min.js"></script> <script> // Enable pusher logging - don't include this in production Pusher.logToConsole = true; var pusher = new Pusher('xxxxxxx', { cluster: 'xxx', forceTLS: true, // デフォルトだと、ドメイン名/pusher/authなので、laravelの認証パスに変更 authEndpoint: 'broadcasting/auth', // csrfトークンがないと認証エラーになる。 auth: { headers: { 'X-CSRF-Token': "{{ csrf_token() }}" } } var channel = pusher.subscribe('private-my-channel'); channel.bind('my-event', function(data) { alert(JSON.stringify(data)); }); </script> |
4, csrfトークン導入で外部からアクセス出来なくはなった。ただ個別のユーザだけに通知したい時に困る(ユーザ識別が出来てないので、全員が受信できる)
laravel5.7だと、最初からuser_id識別用のサンプル・チャネルがあるので、それを使ってみる。
routes/channels.php
1 2 3 |
Broadcast::channel('App.User.{id}', function ($user, $id) { return (int) $user->id === (int) $id; }); |
5, 送信する時のチャンネル文字列にユーザIDを付与する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class MessageCreated implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public $user_id; public $message_text; // Pusherに送る内容 public function __construct(Message $message) { // 発言したユーザID $this->user_id = \Auth::user()->id; // Messageテーブルからテキストだけ $this->message_text = $message->text; } // チャネル名 public function broadcastOn() { // return new PrivateChannel('my-channel'); return new PrivateChannel('App.User.'.$this->user_id); } // イベント名 public function broadcastAs() { return 'my-event'; } } |
6, 受信する側も、チャネル名を自分のユーザIDで修飾(この実装だと、自分から自分へ送っている)
これだと、他のユーザがログインしていても、送信されない(チャネルが違うので)
resources/views/index.blade.php
1 2 3 4 5 6 7 |
//var channel = pusher.subscribe('private-my-channel'); var channel = pusher.subscribe('private-App.User.{{ Auth::id() }}'); channel.bind('my-event', function(data) { alert(JSON.stringify(data)); }); </script> |
7, これでプライベートチャネルは完成。
実際にチャットにするなら、チャット・ルームIDを乱数にしてPrivateChannel名にすればOKかな~。
ユーザIDそのままだと、簡単に推測できてるので、盗聴できてしまう!
もしくは、UserテーブルにIDとは別に乱数KEYを持たせて、それで識別するとか。
正直言って、すごく分かりづらいです…。
https://readouble.com/laravel/5.7/ja/broadcasting.html