I'm using Laravel for a while but I have problem with one thing. Laravel sets cookie for every request. No matter user is logged in or not.
I don't think this is a normal behavior for Laravel. Once a user is logged in we don't need to create new session for them on every request. Do we? So why does laravel generate new session and csrf token for every request that user send? And also it generates these sessions and tokens for guest users too which is completely unnecessary and useless.
How can I prevent this?
Update:
I use Laravel 5.2 and File as session driver.
Here are sample of my routes and middleware:
Routes:
<?php
Route::get('/login', 'UserController#login');
Route::post('/login', 'UserController#postLogin');
Route::get('/link/{link}', 'HomeController#link');
$router->group(['middleware' => ['auth']], function() {
Route::get('/', 'HomeController#index');
Route::post('/', 'HomeController#postindex');
Route::get('/home', 'HomeController#index');
Route::post('/home', 'HomeController#postindex');
Route::get('user/{username}', 'UserController#user_info');
Route::post('user/{username}', 'UserController#post_user_info');
Route::get('/logout', 'UserController#logout');
});
$router->group(['middleware' => ['auth', 'role:2']], function() {
Route::get('/tools/register', 'UserController#register');
Route::post('/tools/register', 'UserController#postregister');
Route::get('/tools/users', 'AdminController#users');
Route::post('/tools/users', 'AdminController#post_users');
});
Route::controllers([
'password' => 'Auth\PasswordController',
]);
Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
];
/**
* The application's route middleware.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'role' => \App\Http\Middleware\Role::class,
];
}
I haven't checked but your route is probably in the default "Web" middleware group that has sessions/cookies/csrf by default.
Laravel Middlewares
Related
So right now I'm using Laravel's default auth for api routes by doing this:
Route::group(['middleware' => ['auth:api']], function() {
...
}
The only thing with this is that it will throw a 401 if a non logged in user hits that page.
What I'm wondering is if there's a way to have a route that will login the user if a token is sent, but if not, they can still hit the api.
I know this will most likely be a custom Middleware, but I don't have a lot of experience with creating Middlewares so I'm not really sure where to start
EDIT
app/Http/Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:1000,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Fruitcake\Cors\HandleCors::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'admin' => \App\Http\Middleware\IsAdmin::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'cors' => \Fruitcake\Cors\HandleCors::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}
Here's a pretty simplified version of my routes api.php file
routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group(['prefix' => 'v2', 'middleware' => ['cors:api']], function() {
//routes that people need to be logged into to do
Route::group(['middleware' => ['auth:api']], function() {
Route::post('/comments/save/{type}/{id}', 'App\Http\Controllers\Api\v2\CommentController#save');
Route::get('/leagues/{id}', 'App\Http\Controllers\Api\v2\LeaguesController#get');;
});
Route::post('/auth/login', 'App\Http\Controllers\Api\v2\AuthController#login');
Route::post('/contact', 'App\Http\Controllers\Api\v2\ContactController#sendMessage');
});
Basically I'm wanting the ability to hit the /leagues/{id} route with either a logged in user or a non logged in user. And if the user is logged in grab the user via Auth::user(). If it helps at all, I'm using React for a front end and sending an api_token in the Authorization header like Bearer $token.
I figured out a way by creating my own custom Middleware. For anyone interested, here it is:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
use App\Models\User;
class OptionalAuthenticate
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$header = $request->header('Authorization');
if(!empty($header)){
$token = str_replace('Bearer ', '', $header);
$user = User::where('api_token', '=', $token)->first();
if(!empty($user)){
Auth::login($user);
}
}
return $next($request);
}
}
I am building a laravel application where I have web and api routes.
I want to store sessions between my routes.
If i store as session without returning a view, it works fine.
But when i return a view my session no longer exists.
My web.php is as follows:
Route::get('/', 'ViewController#index');
Route::get('/check', 'ViewController#check');
My controller
public function index(Request $request)
{
$request->session()->put('test','123456');
$request->session()->save();
//echo $request->session()->get('test', 'default_value');
// return view('welcome'); //If I uncomment this the sessions are not working anymore.
}
public function check(Request $request)
{
echo $request->session()->get('test', 'default_value');
var_dump($request->session()->all());
//return view('welcome');
}
Maybe it has something to do that i also store sessions in my api routes in the api controllers. My api.php:
Route::group(['middleware' => ['web']], function () {
//board
Route::get('/board/create', 'BoardController#create');
Route::post('board/{id}/guess', 'BoardController#guessWord');
Route::get('/board/set', 'BoardController#set');
Route::get('/board/get', 'BoardController#get');
//user
Route::get('/user', 'UserController#get');
Route::post('/user/create', 'UserController#create');
});
kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}
Thanks!
From the docs api routes does not use StartSession middleware because session is only available in web group of middlewares
So store session only in web routes
I understand in Laravel 5.3 they have deprecated Route Filters in favor of middleware. This is discussed here.
I am trying to do something similar but instead of defining a Route pattern I want to define a "filter" where I check the logged in user for a certain condition and redirect the user if this condition is not met. I want this filter to be globally applied to the app.
How can I do this? I only see documentation for the Route::pattern method but Route::filter does not exist.
You can use Laravel Middlewares like this:
To create a new middleware, use the make:middleware Artisan command:
php artisan make:middleware CheckUserAge
And your CheckUserAge.php class should look like this:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckUserAge
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (auth()->user->age <= 20) {
return redirect('home');
}
return $next($request);
}
}
If you want a middleware to run during every HTTP request to your application, simply list the middleware class in the $middleware property of your app/Http/Kernel.php class.
// Within App\Http\Kernel Class...
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
// insert your middleware here <--------------
'checkUserAge' => \App\Http\Middleware\CheckUserAge::class,
];
Out of the box, the web middleware group is automatically applied to your routes/web.php file by the RouteServiceProvider.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\CheckUserAge::class, // <------- add here too
],
];
See more about Middlewares in Laravel
Hope this helps!
So I'm following along with the Laravel 5 fundamentals tutorial and I am stuck on the form validation. I have followed along exactly with the tutorial but I am getting a Undefined variable: errors in my create articles view.
In the tutorial I am following and what I have found online they say the errors variable is always there in the blade file for you to use so I don't know what i am doing wrong?
Any help would be appreciated! loving Laravel except for this error!
View
#if($errors->any())
<ul class="alert alert-danger">
#foreach($errors->any() as $error)
<li>{{$error}}</li>
#endforeach
</ul>
#endif
Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use App\Http\Requests;
use App\Http\Requests\UserRequest as UserRequest;
// use App\Http\Requests\CreateArticleRequest as CreateArticleRequest;
use App\Http\Controllers\Controller;
use Illuminate\View\Middleware\ErrorBinder;
class UserController extends Controller
{
public function create(){
return view('pages.signUp');
}
public function store(UserRequest $request){
User::create($request->all());
return 'the user has been registered!';
return view('user.profile');
}
}
Request validation
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class UserRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required',
'email' => 'required|email',
'country' => 'required',
'password' => 'required|min:6',
'confirm_password' => 'required|same:password',
'height' => 'required',
'weight' => 'required',
];
}
}
This is a breaking problem with the 5.2 upgrade. What's happening is the middleware which is responsible for making that errors variable available to all your views is not being utilized because it was moved from the global middleware to the web middleware group.
There are two ways to fix this:
In your kernel.php file, you can move the middleware \Illuminate\View\Middleware\ShareErrorsFromSession::class back to the protected $middleware property.
You can wrap all your web routes with a route group and apply the web middleware to them.
Route::group(['middleware' => 'web'], function() {
// Place all your web routes here...
});
Solved
You may change any one of the following:
1. put your working route (app/http/routes.php) on
Route::group(['middleware' => ['web']], function () {
// Here like
Route::get('/', 'TodoController#index');
Route::post('/', 'TodoController#store');
});
Screenshot -
2. Move your protected $middlewareGroups web (app/Http/Kernel.php) on protected $middleware = []
Screenshot -
This is solution:
Change the defination of your Route groups with a middleware, from :
Route::group(['middleware' => 'web'], function () {
to
Route::group(['middlewareGroups' => 'web'], function () {
Source: https://github.com/laravel/framework/issues/13000
simply, you have to move :
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
from protected $middlewareGroups to protected $middleware
Just remove , 'middleware' => 'web' from Route::group(array('prefix' => 'user', 'middleware' => 'web'), function() in routes.php page OR
Move
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
From protected $middlewareGroups to protected $middleware in kernel.php page
As the Laravel Documentation says:
Note: If your copy of Laravel has a RouteServiceProvider that already
includes the default routes file within the web middleware group, you
do not need to manually add the group to your routes.php file.
So removing from routes.php file would be the correct way.
Posting this as it might be useful for others,
As Smartrahat mentioned in 1st solution, in your Kernel.php file(app/Http/Kernel.php) move \Illuminate\View\Middleware\ShareErrorsFromSession::class
from $middlewareGroups to protected $middleware property, but the same will start throwing the error "Session store not set on request",
to resolve this move
\Illuminate\Session\Middleware\StartSession::class, to $middleware property as well.
As of 5.2, routes.php is by default already called in the context of a ['middleware'=>'web'] by RouteServiceProvider. But in routes.php default generation of auth routes, the Route::group call is still happening by default - so if you delete that Route::group declaration from routes.php the application then correctly shows errors.
A couple of observations regarding this issue. First off there a related bug in github regarding this issue
PFA
https://github.com/laravel/framework/issues/12022
If you look at the last comment which Graham wrote, I think that is the facing I was facing.
For me even though there was a error in form post data, I was getting the below equality
boolval(count($errors) === 0) === true
In my case I added log statements in the
\Illuminate\Session\Middleware\StartSession::class
the above middleware class ran twice for a given request, I am not sure why it ran twice, but I think because of this the $errors variable is getting reset.
I was using this configuration (which I think came default with Laravel#5.2.43)
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
I changed the configuration which worked for me and the $errors variable's count is not zero (also the above middleware ran only once per request)
protected $middleware = [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
Note:
All my routes are in the web middleware group before and after the Kernel.php configuration change, I didnot move my routes at all from the web middleware group.
Change #foreach($errors->any() as $error) to #foreach($errors->all() as $error)
in this case laravel 5.2 you can refer may example code and edit your kernal.php file. move this \Illuminate\View\Middleware\ShareErrorsFromSession::class, form middlewareGroups to middleware and add \Illuminate\Session\Middleware\StartSession::class, to middleware
then its work correctly.
Having both Web and API requirements in our application, we did not want to move the middleware around; perhaps that would have worked, however:
We had the very peculiar situation that the flash[] and $errors session data was transmitted correctly between the standard laravel resource methods, store() and edit(), but in some cases the data did not get back across nearly identical methods, storeSale() and editSale().
We found that in our development and deployment environments, the 'file' and 'database' session drivers worked in all cases, but the 'cookie' driver did not.
Switching to the database driver in all instances solved the problem.
I'm using: Laravel Framework version 5.1.24 (LTS), and I am having great difficulty with implementing a Middleware route group.
Here is what I have in my routes.php:
Route::group(['middleware' => 'api'], function () {
Route::get('api/users', 'UserController#getUsers');
Route::get('api/user/{id}', 'UserController#viewUser');
Route::post('api/user', 'UserController#addUser');
Route::put('api/user/{id}', 'UserController#updateUser');
Route::delete('api/user/{id}', 'UserController#deleteUser');
});
I've also added this to the $routeMiddleware array within Kernel.php:
'api' => \App\Http\Middleware\ApiAuthenticate::class,
I have the ApiAuthtenticate Middleware set to run before continuing, so I'm expecting to see the error handling I have in there, but I am not. What I do get is the MethodNotAllowedHttpException exception thrown.
The strange thing is if I remove the Middleware route group, and add the ApiAuthenticate class to the $middleware array within Kernel.php, it behaves exactly as it should (throws my Exceptions). However, I want to use the Middleware on a specified group of routes, not on the entire global scope.
Can someone please help?
Here is the Middleware:
namespace App\Http\Middleware;
use Closure;
use Session;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ApiAuthenticate
{
public function handle($request, Closure $next)
{
if ($request->header('content-type') != 'application/x-www-form-urlencoded') {
throw new BadRequestHttpException('The request must be: Content-Type: application/x-www-form-urlencoded');
}
return $next($request);
}
From Kernel.php:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
//\App\Http\Middleware\VerifyCsrfToken::class,
//\App\Http\Middleware\ApiAuthenticate::class,
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'api' => \App\Http\Middleware\ApiAuthenticate::class,
];