Setting Cookie in Laravel Custom Middleware - laravel

I want to set a cookie in a custom Laravel middleware. The idea is to set the cookie value any time a user visits my website through any landing page.
So what I did was I created a middleware named UUIDMiddleware. I am using this middleware along with web middleware in my routes. Below is its code from the middleware.
if($request->hasCookie('uuid'))
{
return $next($request);
}
else
{
$uuid = Uuid::generate();
$response = new Response();
return $response->withCookie(cookie()->forever('uuid', $uuid));
}
As you can see I am checking if cookie exists. If not, I am passing control to next request.
The problem is when setting a cookie using return $response, I cannot pass control to next request. How do I resolve this?
What happens in this case is if a cookie is not set, it sets a cookie and a blank screen shows up. If I refresh, I see the website with a cookie set.
There has to be a way to set cookie using middleware in the right way. How do I do it?

The response object in middleware is returned by the $next closure, so you could do something like this:
if($request->hasCookie('uuid')) {
return $next($request);
}
$uuid = Uuid::generate();
return $next($request)
->withCookie(cookie()->forever('uuid', $uuid));

If you're using Laravel 5.8 and like me you want a solution that allows you set the expiration time of the cookie instead of setting it to forever, you could also do something like this in the middleware:
public function handle($request, Closure $next)
{
$time = time() + 60 * 60 * 24; //One day
$res = $next($request);
return $res->cookie('cookie_name', $cookieValue, $time, "/");
}
This would set the cookie when the controller is done with the request and is returning a response.

Related

Unable to retrieve cookies set by Laravel

According to the official docs on cookies:
By default, all cookies generated by Laravel are encrypted and signed so that they can't be modified or read by the client. If you would like to disable encryption for a subset of cookies generated by your application, you may use the $except property of the App\Http\Middleware\EncryptCookies middleware, which is located in the app/Http/Middleware directory
In my controller that sends a response with cookies, I set a cookie with return response("Success", 200)->cookie('api_token', $api_token, 2, '/');, where $api_token is a string generated by Str::random(80). I have a route in web.php that is protected by middleware that checks if the cookie is valid. However, using $request->cookie('api_token'); in the middleware returns nothing, but I have to make an exception in the EncryptCookies for api_token to make this work.
I'm not sure why my cookie isn't being encrypted, even if I use a laravel function to set it. Am I misunderstanding which cookies are "generated" by Laravel?
Set Cookies :
public function setCookie(Request $request){
$minutes = 60;
$response = new Response('Set Cookie');
$response->withCookie(cookie('name', 'MyValue', $minutes));
return $response;
}
Get Cookies :
public function getCookie(Request $request){
$value = $request->cookie('name');
echo $value;
}

How to set middleware to kc finder

I have set Session after I login
session_start();
$_SESSION['ckfinder_auth'] = true;
where can I set middleware in this path
/templateEditor/kcfinder/browse.php?opener=ckeditor&type=images&CKEditor=editor1&CKEditorFuncNum=1&langCode=en
When you work with Laravel, it's best to write your own codes based on Laravel.
For example, To store data in the session, you will typically use the putmethod or the session helper:
// Via a request instance...
$request->session()->put('key', 'value');
or
// Via the global helper...
session(['key' => 'value']);
for retrieving an item from the session, you can use get :
$value = $request->session()->get('key', 'default value');
or global session helper :
$value = session('key', 'default value');
To determine if an item is present in the session, you may use the has method:
if ($request->session()->has('users')) {
//
}
I suggest you read the Laravel document first (session , middleware)
You have to create a new middleware and add it to the Kernel.php file
php artisan make:middleware <middleware_name>
Change the handle($request, Closure $next) as per your requirements.
Update the /App/Http/Kernel.php file by adding your middleware to protected $routeMiddleware = [] array
Now you have setup adding middleware. Simple add this middleware to the routes by calling
Routes::middleware(['middleware_name'])->get(function(){
return view('your_view');
});

JWT::getToken() doesn't get the proper token

I'm using JWT-Auth for authentication. I have created a middleware that checks if token is expired and then it refreshes the token and update the header. But in my controller getToken() does not get the new token but returns the expired one. I have checked the value of header in my controller and it has the new token.
This is how I do it in my middleware:
$new_token = JWTAuth::refresh($token);
$request->headers->set('Authorization', 'Bearer '.$new_token);
$response = $next($request);
and this is in my controller:
$token = JWTAuth::getToken();
After looking at their code. I found a setToken() function which solved my issue. I modified my code like this:
$new_token = JWTAuth::refresh($token);
JWTAuth::setToken($new_token);
$response = $next($request);
$response->header('Authorization','Bearer '.$new_token);
return $response;
Change version of JWT package 5.12 to 5.11 in composer.json file then its work properly.
I was also stuck in same issue before few days
https://github.com/tymondesigns/jwt-auth/issues/1198

Laravel 5 - Remove Parameter From All Request Objects at Controller Level

I have URLs that look like:
http://example.com/api/user?id=45&name=mike&api_token=2348283
http://example.com/api/project?id=5&description=first&api_token=2348283
etc...
In my controllers, I have functions that look like:
public function user_get_endpoint(Request $request){
$request = $request->toArray();
return UserModel::where($request)->get()->toArray();
}
The above will currently break since the $request object contains a property called api_token which does not exist in the user table. I am using the api_token in a middleware to check for authentication.
I can manually unset the api_token property in each of my API functions by using unset($request['api_token'], but I'd like to avoid that if possible.
Is there anyway to do this application wide or at a class or controller level?
Laravel provides add and remove functions to add and remove new properties to the request object respectively.
$request->request->add(['api_token' => 'api_token']); // to add new property to $request
$request->request->remove('api_token'); // to remove property from $request
Perhaps you want global middleware?
First arrange for the middleware to run on all routes:
// routes.php
$app->middleware([
App\Http\Middleware\Apitoken::class
]);
Then define what the middleware should do:
// src/App/Http/Middleware/Apitoken.php
<?php
namespace App\Http\Middleware;
use Closure;
class Apitoken
{
public function handle($request, Closure $next)
{
unset($request['api_token']);
return $next($request);
}
}
Method 1
$request->except(['key1','key2',....])
provides an easy way to skip unwanted keys, similarly
Method 2
$request->only(['key3','key4',....])
provides an easy way to skip all others unwanted keys, I find both reasonably good for almost all scenarios
A solution that works for all HTTP Methods (not only for GET and HEAD) :
$except = ['api_token'];
$request = request();
$cleanup = $request->except($except);
$request->query = new \Symfony\Component\HttpFoundation\ParameterBag($cleanup);
Ideally, you should send your api_token in request headers instead of Uri params.
If you are using Laravel's auth:api Middleware for authentication then you can send api_token in headers as:
$response = $client->request('GET', '/api/user', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
],
]);
Then api_token will never come in your Uri params.
As #JanWillem said in the comments you can use except() which will remove the params you pass to it:
public function user_get_endpoint(Request $request){
return UserModel::where($request->except('api_token'))->get();
}
https://laravel.com/docs/5.2/requests#retrieving-input and then scroll down to Retrieving A Portion Of The Input Data
Furthermore, you don't have to use toArray() with the response as Laravel will automatically do this for you.
Hope this helps!

Laravel 5 : Does Auth::user() query the database everytime I use it?

On the edit profile page for a user, I want to show the existing values of the current logged-in user details like name, email, gender etc. My questions are as follows
Is it recommendable to user Auth::user()->name , Auth::user()->email directly to populate the form fields ? Or shall I create a variable like $user = Auth::user(); in my controller and pass it on to my view to $user like a regular object?
Does using Auth::user(), multiple times on a given view file hit my database each time I use it?
Thanks in advance.
If you look at the SessionGuard.php file in Illuminate\Auth, you'll see the method user() which is used to retrieve the currently authenticated user:
/**
* Get the currently authenticated user.
*
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
if ($this->loggedOut) {
return;
}
// If we've already retrieved the user for the current request we can just
// return it back immediately. We do not want to fetch the user data on
// every call to this method because that would be tremendously slow.
if (! is_null($this->user)) {
return $this->user;
}
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
$user = null;
if (! is_null($id)) {
if ($user = $this->provider->retrieveById($id)) {
$this->fireAuthenticatedEvent($user);
}
}
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
// pull the user data on that cookie which serves as a remember cookie on
// the application. Once we have a user we can return it to the caller.
$recaller = $this->getRecaller();
if (is_null($user) && ! is_null($recaller)) {
$user = $this->getUserByRecaller($recaller);
if ($user) {
$this->updateSession($user->getAuthIdentifier());
$this->fireLoginEvent($user, true);
}
}
return $this->user = $user;
}
// If we've already retrieved the user for the current request we can just return it back immediately. We do not want to fetch the user data on every call to this method because that would be tremendously slow.
if (! is_null($this->user)) {
return $this->user;
}
So, calling the user() multiple times won't make multiple calls to the database.
You'll get only 1 request to database, so using Auth::user() multiple times is not a problem.
I recommend you using Laravel Debugbar as the most comfortable way for app optimization.

Resources