Laravel is not sending Pusher Events to my Vue.js frontend - laravel

I have a Vue.js separated project from a Laravel backend in many tutorials I see a Laravel + Vue.js but I have a Vue.js SPA separated and I don`t know what I doing wrong.
I already make the configuration on front end, this is it:
const pusher = new Pusher(configMain.PUSHER_APP_KEY, {
cluster: configMain.PUSHER_APP_CLUSTER
});
const pusherChannel = pusher.subscribe('teste');
pusherChannel.bind('my-event', function(data) {
console.log(data);
});
When I use the debug console in PUSHER and send an event, it works fine I receive it. But when I try to send an event from my backend Laravel project it doesn`t work.
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=********
PUSHER_APP_KEY=********
PUSHER_APP_SECRET=********
PUSHER_APP_CLUSTER=********
I already set the keys and change the driver, in config broadcasting i have this:
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
],
],
I created an event in Laravel that is this:
<?php
namespace App\Events;
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 MyEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
private $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($message)
{
//
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('teste');
}
public function broadcastAs()
{
return 'my-event';
}
}
And when i execute this in my backend:
event(new MyEvent('hello world'));
dd("ENTROU");
My front doesn't receive it, I must do something that I don't see it?

Related

Laravel 9: User not authenticated on API routes using custom guard

I need to authenticate temporary users of a third party app. In addition, users only get a signed URL to login (there is no username/password). The temporary users get created on the fly and logged in after verifying the signed URL and some query params. Because I also have "traditional" users in my app I am using an additional database table called "clients", an additional provder 'clients' and an additional guard called 'vcs' for the authentication workflow.
The authentication workflow (user clicks on the signed URL, a new Client is created and saved to the database as well as logged in as new user) is working fine. The session is created correctly and send to the browser in the laravel_session cookie. The problem is, that all subsequent requests to my API seem to be unauthenticated.
config/auth.php:
<?php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'vcs' => [
'driver' => 'session',
'provider' => 'clients',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'clients' => [
'driver' => 'eloquent',
'model' => App\Models\Client::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => 10800,
];
My client model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Client extends Authenticatable
{
use HasFactory, HasApiTokens;
protected $guard = "vcs";
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'uuid';
/**
* Indicates if the model's ID is auto-incrementing.
*
* #var bool
*/
public $incrementing = false;
protected $keyType = 'string';
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'uuid';
}
}
The clients get a signed URL which points to the following controller action. The action checks for a valid query parameter in the URL (simplified for this thread). After that a new Client model gets created and the new Client gets logged in using the 'vcs' guard:
<?php
namespace App\Http\Controllers\VCS;
use Illuminate\Http\Request;
use App\Models\Client;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function redirectWithCookie(Request $request)
{
// reduced for the sake of simplicity here
$credential = $request->someURLParameter;
if ($credential) {
$client = new Client;
$client->uuid = Str::uuid()->toString();
$client->ip = $request->ip();
$client->status = 'pending';
$client->save();
Auth::guard('vcs')->login($client, $remember = true);
// this logs the authenticated user correctly!
Log::info('Authenticated User: ' . Auth::guard('vcs')->user());
$cookieValue = json_encode(array('uuid' => $client->uuid));
$cookie = cookie('mycookie', $cookieValue);
$redirectUrl = config('my.redirect.url');
return redirect()->away($redirectUrl)->withCookie($cookie);
}
return response(['message' => 'Invalid URL', 'error' => 'url'], 422);
}
}
routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\VCS\AuthController;
Route::get('/', function () {
return ['Laravel' => app()->version()];
});
Route::get('vcs/auth', [AuthController::class, 'redirectWithCookie'])->name('vcs.auth');
require __DIR__.'/auth.php';
routes/api.php:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\VCS\RoomController;
Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
return $request->user();
})->name('profile');
Route::middleware(['auth:vcs'])->group(function () {
Route::get('rooms', [RoomController::class, 'rooms']);
});
After the redirect I get a laravel_session as a cookie which should authenticate my subsequent requests. The problem is that I can't call any API routes with the custom guard and I am not authenticated anymore although the browser is sending my session cookie with the request. For example calling the /api/rooms GET-endpoint defined in the api.php results in a redirect to the login page.
I also see that the user is not authenticated in the auth-middleware:
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string|null
*/
protected function redirectTo($request)
{
Log::info('Authenticated User: ' . Auth::guard('vcs')->user());
}
}
The Log just returns an empty string so the user is not authenticated:
[2022-11-06 13:44:30] local.INFO: Authenticated User:
So my question is: How can I use a custom guard for my API routes after manually logging new users in?
I also tried the same workflow using Insomnia as a REST Client:
Login by URL:
whichs gives me a sessions cookie.
Access some API Route:
Which results in an Unauthorized-Status-Code..

How can i send a laravel email with SMTP without getting the .env data?

I need to fetch the SMTP data in the account of user that will be saved in the database. That way it couldn't pull the data from the .env file.
I'm using Laravel 8
For example, instead of looking for SMTP authentication in .env I would look in the database:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Mail;
use Config;
use App\Mail\EmailManager;
class NewsletterController extends Controller
{
public function testEmail(Request $request){
$array['view'] = 'emails.newsletter';
$array['subject'] = "SMTP Test";
$array['from'] = 'email#email.com';
$array['content'] = "This is a test email.";
Config::set('mail.host', 'smtp.mailtrap.io');
Config::set('mail.username', 'email#email.com');
Config::set('mail.password', 'd13ea2a29a5cee');
Config::set('mail.port', 587);
try {
Mail::to($request->email)->send(new EmailManager($array));
} catch (\Exception $e) {
dd($e);
}
flash(translate('An email has been sent.'))->success();
return back();
}
}
I solved.
I Created a file with configutations:
/app/Providers/MailConfigServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
use App\Models\EmailSetting;
use Config;
class MailConfigServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
if (\Schema::hasTable('email_settings')) {
$mail = DB::table('email_settings')->first();
if ($mail) //checking if table is not empty
{
$config = array(
'driver' => $mail->driver,
'host' => $mail->host,
'port' => $mail->port,
'from' => $mail->from,
'encryption' => $mail->encryption,
'username' => $mail->username,
'password' => $mail->password,
'sendmail' => '/usr/sbin/sendmail -bs',
'pretend' => false,
);
Config::set('mail', $config);
}
}
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
}
}
And added this line on app/config
App\Providers\MailConfigServiceProvider::class

Pusher receive event with null values

I'm using laravel 5.8 version. I'm sending a message to pusher but put pusher receive event {"message": null}.
Here is my broadcasting.php file
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
// 'cluster' => env('PUSHER_APP_CLUSTER'),
// 'useTLS' => true,
'cluster' => 'ap2',
'useTLS' => true
],
],
There is my chatevent.php file.
namespace App\Events
use Illuminate\Broadcasting\Channel;
use Illuminate\Foundation\Auth\User;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ChatEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $user;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($message, User $user)
{
$this->$message = $message;
$this->$user = $user;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
There is my bootstrap.js file.
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
// broadcaster: 'pusher',
// key: process.env.MIX_PUSHER_APP_KEY,
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
// encrypted: truebroadcaster: 'pusher',
broadcaster: 'pusher',
key:'REDACTED',
cluster: 'ap2',
encrypted: true
});
My controller function where I'm sending message to pusher.
public function send()
{
$message = 'hello';
$user = User::find(Auth::id());
event(new ChatEvent($message, $user));
}
}
How to fix it????
I think you write the constructor of your event class wrong.
Here you put extra $ before message and user variable
public function __construct($message, User $user)
{
$this->$message = $message;
$this->$user = $user;
}
It should be like following one.
public function __construct($message, User $user)
{
$this->message = $message;
$this->user = $user;
}

Laravel Echo not listening

I am trying to create a real-time post using Laravel with ReactJS and Pusher. I have been able to create pusher events and i could see the events showing on the pusher site. However, Laravel echo does not listen to the event whenever it is created and i cannot figure out why or how to make it to listen.
App\Events\PostCreated
<?php
namespace App\Events;
use App\Post;
use App\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class PostCreated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $post;
public $user;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Post $post, User $user)
{
//
$this->post = $post;
$this->user = $user;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return [
new PrivateChannel('new-post'),
new PrivateChannel('App.User.' . $this->post->user->id),
];
}
/**
* #return array
*/
public function broadcastWith() {
return [
'post' => array_merge($this->post->toArray(), [
'user' => $this->post->user,
]),
'user' => $this->user,
];
}
}
broadcasting.php
/*
|--------------------------------------------------------------------------
| Broadcast Connections
|--------------------------------------------------------------------------
|
| Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array.
|
*/
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => getenv('PUSHER_APP_KEY'),
'secret' => getenv('PUSHER_APP_SECRET'),
'app_id' => getenv('PUSHER_APP_ID'),
'options' => [
'cluster' => getenv('PUSHER_APP_CLUSTER'),
'encrypted' => true,
],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
'log' => [
'driver' => 'log',
],
'null' => [
'driver' => 'null',
],
],
.env
BROADCAST_DRIVER=pusher
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
PUSHER_APP_ID=757605
PUSHER_APP_KEY=4100ca8b118192fd01b2
PUSHER_APP_SECRET=41f43d23204a3c7ae2a7
PUSHER_APP_CLUSTER=ap1
bootstrap.js
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
//const client = require('pusher-js');
//import 'pusher-js/node';
window.Echo = new Echo({
broadcaster: 'pusher',
key: '4100ca8b118192fd01b2',
cluster: 'ap1',
encrypted: true
});
channels.php
<?php
/*
|--------------------------------------------------------------------------
| Broadcast Channels
|--------------------------------------------------------------------------
|
| Here you may register all of the event broadcasting channels that your
| application supports. The given channel authorization callbacks are
| used to check if an authenticated user can listen to the channel.
|
*/
use Illuminate\Support\Facades\Auth;
Broadcast::channel('App.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
Broadcast::channel('new-post', function ($user) {
return Auth::check();
});
PostController
public function create(Request $request, Post $post) {
$data = [];
$video_data = [];
if ($request->get('file')) {
foreach ($request->get('file') as $file) {
$name = md5(uniqid()) . '.' . explode('/', explode(':', substr($file, 0, strpos($file, ';')))[1])[1];
$upload = Uploader::upload($file, array('public_id' => $name));
array_push($data, $upload['secure_url']);
}
}
if ($request->get('video')) {
foreach ($request->get('video') as $file) {
$name = md5(uniqid() . '.' . explode('/', explode(':', substr($file, 0, strpos($file, ';')))[1]))[1];
$upload = Uploader::upload($file, array('public_id' => $name, 'resource_type' => 'video'));
array_push($video_data, $upload['secure_url']);
}
}
$image = !empty($data) ? json_encode($data) : null;
$video = !empty($video_data) ? json_encode($video_data) : null;
$body = $this->test_data($request->body);
// create post
$createdPost = $request->user()->posts()->create([
'body' => $body,
'image' => $image,
'video' => $video
]);
// broadcast
broadcast(new PostCreated($createdPost, $request->user()))->toOthers();
// return the response
return response()->json($post->with('user')->find($createdPost->id));
}
app.blade.php (App Layout)
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
'user' => [
'id' => Auth::check() ? Auth::user()->id : null,
'following' => Auth::check() ? Auth::user()->following()->pluck('users.id') : null
],
]);
?>
</script>
ReactJS (Frontend)
componentDidMount() {
Echo.private('new-post').listen('PostCreated', (e) => {
if (window.Laravel.user.following.includes(e.post.user_id)) {
this.setState({ posts: [e.post, ...this.state.posts] });
}
});
// this.interval = setInterval(()=>this.getPosts(), 10000);
}
I expect the followers of the user that created a new post to see the post instantly without reloading the page but instead, nothing happens.
The event is created but it is not listened to. What am i doing wrong?
try to set broadcastAs in your event class and explicitly set the broadcast name in reactjs part.
App\Events\PostCreated
<?php
namespace App\Events;
class PostCreated implements ShouldBroadcast
{
// other code
public function broadcastAs()
{
return 'PostCreated';
}
}
ReactJS (Frontend)
componentDidMount() {
Echo.private('new-post').listen('.PostCreated', (e) => {
if (window.Laravel.user.following.includes(e.post.user_id)) {
this.setState({ posts: [e.post, ...this.state.posts] });
}
});
// this.interval = setInterval(()=>this.getPosts(), 10000);
}
notice that I use .PostCreated ( and not PostCreated). By, default, laravel has convention on the broadcast name. I prefer explicit programming style so I usually set broadcastAs for all my events.
I was able to figure it out and noticed that i have to keep running the following command:
php artisan queue:listen

Laravel Spark not sending message to Pusher from event

Trying to get Pusher working on my app but cannot get it to send any messages to Pusher itself.
I have an event that is fired when creating a 'booking':
event(new BookingCreated($booking));
This event:
<?php
namespace App\Events\Booking;
use App\Booking;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class BookingCreated implements ShouldBroadcast
{
use SerializesModels, InteractsWithSockets;
public $booking;
/**
* Create a new event instance.
*
* #param Booking $booking
* #return void
*/
public function __construct(Booking $booking)
{
$this->booking = $booking;
}
public function broadcastOn()
{
return ['teams.'.$this->booking->team_id.'.bookings'];
}
}
My env file has the following (with details):
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
My broadcasting config file has the pusher details set up as:
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => 'eu'
],
],
When looking in the Pusher dashboard I can see open connections, but no messages. I am running queue:listen which is showing that the events are being processed.
Anything I am missing?
This was a mistake on my behalf, I had changed the env file BROADCAST_DRIVER but hadn't restarted the queue listener so my events were broadcasting to the log.

Resources