Laravel broadcasting với pusher
Cài đặt gói pusher vào trong app laravel :
composer require pusher/pusher-php-server
Sau đó chúng ta sẽ tạo route xác thực :
Route::post('/pusher/auth', [\App\Http\Controllers\UserController::class, 'useauth_private'])->name('userauth');
Route::post('/pusher/presenceauth', [\App\Http\Controllers\UserController::class, 'useauth_presence'])->name('presenceauth');
Phương thức useauth_private trong UserController :
public function useauth_private(Request $request)
{
$pusher = new Pusher(env('PUSHER_APP_KEY'),env('PUSHER_APP_SECRET'),env('PUSHER_APP_ID'),[
'cluster'=>env('PUSHER_APP_CLUSTER')
]);
$user_id = Auth::id();
Log::info($user_id);
$channel_name = $request->channel_name;
if ($channel_name !== 'private-chat-' . $user_id && $channel_name !== 'private-order-' . $user_id) {
return response()->json(['message' => 'Unauthorized'], 403);
}
// Trả về thông tin user cho presence channel
return response($pusher->authorizeChannel($request->channel_name, $request->socket_id));
}
Phương thức userauth_presence
public function useauth_presence(Request $request){
if (!Auth::check()) {
return response()->json(['message' => 'Unauthorized'], 403);
}
$pusher = new Pusher(
env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'),
env('PUSHER_APP_ID'),
['cluster' => env('PUSHER_APP_CLUSTER')]
);
$user = Auth::user();
$presence_data = [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email
];
return response($pusher->authorizePresenceChannel($request->channel_name, $request->socket_id, $presence_data));
}
Trong file .env :
PUSHER_APP_ID="2222"
PUSHER_APP_KEY="2222"
PUSHER_APP_SECRET="2222"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
PUSHER_APP_CLUSTER="ap1"
Trong file : bootstrap/app.php thêm đoạn code :
$middleware->validateCsrfTokens(['/pusher/auth','/pusher/presenceauth']);
để loại bỏ csrf với các url
Còn ở frontend blade :
<!-- Pusher -->
<script src="https://js.pusher.com/8.2.0/pusher.min.js"></script>
<script>
// comment để bỏ log dòng sau :
Pusher.logToConsole = true;
var pusher = new Pusher('{{ env('PUSHER_APP_KEY') }}', {
cluster: 'ap1',
userAuthentication:{
endpoint: "{{ route('userauth') }}",
params: {
_token: document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
},
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '',
'Content-Type': 'application/json',
'Accept': 'application/json'
},
customHandler: null,
},
presenceAuthentication: {
endpoint: "{{ route('presenceauth') }}",
transport: 'ajax',
params: {
_token: document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
},
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '',
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}
});
var userId = "{{ \Illuminate\Support\Facades\Auth::id() ?? '' }}"; // Nếu user chưa đăng nhập thì là ''
if (userId) {
var private_channel = ['private-chat-', 'private-order-'];
private_channel.forEach((channel) => {
const subscribedChannel = pusher.subscribe(channel + userId);
subscribedChannel.bind("chat", function (data) {
console.log("New private event:", data);
alert(JSON.stringify(data));
});
});
var presence_channel = ['presence-chat', 'presence-order'];
presence_channel.forEach((channel) => {
const subscribedChannel = pusher.subscribe(channel);
// Lắng nghe sự kiện khi có người dùng mới tham gia kênh
subscribedChannel.bind("pusher:subscription_succeeded", function (members) {
console.log("🔹 User list:", members);
document.getElementById("messages").innerHTML += "<p>✅ Connected to presence channel: " + channel + "</p>";
});
// Lắng nghe khi có người tham gia
subscribedChannel.bind("pusher:member_added", function (member) {
console.log("➕ New member joined:", member);
});
// Lắng nghe khi có người rời khỏi
subscribedChannel.bind("pusher:member_removed", function (member) {
console.log("❌ Member left:", member);
});
// Lắng nghe tin nhắn trong kênh
subscribedChannel.bind("chat", function (data) {
console.log("📩 Presence Chat:", data);
alert(JSON.stringify(data));
});
});
}
var public_channel = ['public-chat', 'public-order'];
public_channel.forEach((channel) => {
const subscribedChannel = pusher.subscribe(channel);
subscribedChannel.bind("chat", function (data) {
console.log("New public event:", data);
document.getElementById("messages").innerHTML += "<p>" + data.message + "</p>";
alert(JSON.stringify(data));
});
});
</script>
Trong controller ta code như sau để dùng broadcast public và private :
<?php
namespace App\Http\Controllers;
use App\Events\PrivateEvent;
use App\Events\Pusher\PublicEvent;
use App\Events\ThongbaoEvent;
use Illuminate\Http\Request;
class NotificationController extends Controller
{
public function public()
{
$message = 'Xin chào';
broadcast(new PublicEvent($message));
return response()->json(['message' => 'Notification pusher public sent']);
}
public function private(){
$message = 'Xin chào private test channel';
broadcast(new \App\Events\Pusher\PrivateEvent($message,2));
return response()->json(['message' => 'Notification private sent']);
}
}
Event Public :
<?php
namespace App\Events\Pusher;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PublicEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public $message;
public function __construct($message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn()
{
return [
new Channel('public-chat'),
];
}
public function broadcastAs(){
return 'chat';
}
}
Event Private :
<?php
namespace App\Events\Pusher;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class PrivateEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public $message;
public $user_id ;
public function __construct($message,$user_id)
{
$this->user_id = $user_id;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn()
{
$tenchanel = 'private-chat-'.$this->user_id;
Log::info($tenchanel);
return [
new PrivateChannel($tenchanel),
];
}
public function broadcastAs(){
return 'chat';
}
public function broadcastWith(){
return [
'message' => $this->message,
];
}
}
Như vậy là đã xong .Ở đây mình đã test private còn presence thì chưa nhé