I'm trying to implement some custom flash messages and I'm having some issues with the session data being destroyed after a redirect.
Here's how I create my flash messages :
flash('Your topic has been created.');
Here's the declaration of the flash() function :
function flash($message, $title = 'Info', $type = 'info')
{
session()->flash('flash', [
'message' => $message,
'title' => $title,
'type' => $type,
]);
}
And here is how I'm checking the session/displaying the flash messages, using SweetAlerts. This code is included at the bottom of the main layout file that I'm extending in all my Blade templates.
#if(Session::has('flash'))
<script>
$(function(){
swal({
title: '{{ Session::get("flash.title") }}',
text : '{{ Session::get("flash.message") }}',
type : '{{ Session::get("flash.type") }}',
timer: 1500,
showConfirmButton: false,
})
});
</script>
#endif
The code above will work if I call the flash() function before displaying a view, like so :
public function show($slug)
{
flash('It works!');
return view('welcome');
}
However, it will not work if I call it before doing a redirect to another page, like so :
public function show($slug)
{
flash('It does not work');
return redirect('/');
}
Why is the session data lost on redirect? How can I make it persists so that I can display my flash message?
I found out that it is necessary to apply the web middleware on all routes. Drown has mentioned to do so, but since March 23st 2016, Taylor Otwell changed the default RouteServiceProvider at https://github.com/laravel/laravel/commit/5c30c98db96459b4cc878d085490e4677b0b67ed
By that change the web middleware is applied automatically to all routes. If you now apply it again in your routes.php, you will see that web appears twice on the route list (php artisan route:list). This exactly makes the flash data discard.
Also see: https://laracasts.com/discuss/channels/laravel/session-flash-message-not-working-after-redirect-route/replies/159117
It turns out that with Laravel 5.2, the routes have to be wrapped in the web middleware for the session to work properly.
This fixed it :
Route::group(['middleware' => ['web']], function () {
// ...
Route::post('/topics/{slug}/answer', 'PostsController#answer');
Route::post('/topics/{slug}/unanswer', 'PostsController#unanswer');
Route::post('/topics/{slug}/delete', 'PostsController#delete');
});
Please check APP/kernel.php
\Illuminate\Session\Middleware\StartSession::class,
is define multiple times
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Session\Middleware\StartSession::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,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
You can comment any one or delete it. We need to define one time only.
The issue i had was Session::save() preventing swal from showing after redirect.
so you need to remove Session::save() or session()->save(); from middleware
With Laravel 5.2.34, all routes are using web middleware by default.
Therefore, change this:
Route::group(['middleware' => ['web']], function () { // This will use 2 web middleware
// ...
Route::post('/foo', 'FooController#foo');
});
To this:
Route::group([], function () { // This will use the default web middleware
// ...
Route::post('/foo', 'FooController#foo');
});
And then in your controller you could use:
class FooController extends Controller
{
...
public foo()
{
...
return redirect('/foo')->withSuccess('Success!!');
// or
return redirect('/foo')->with(['success' => 'Success!!']);
}
...
}
Redirect with flash data is done like this:
redirect("/blog")->with(["message"=>"Success!"]);
In early Laravel 5.2 versions, all of your Flash and Session data are stored only if your routes are inside web middleware group.
As of Laravel 5.2.34, all routes are using web middleware by default. If you will put them into middleware web group again, you will apply web middleware on your routes twice - such routes will be unable to preserve Flash or Session data.
Check your App\Kernel.php file.
There may be multiple lines of \Illuminate\Session\Middleware\StartSession::class,
Comment one from $middlewareGroups.
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
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,
],
have you tired using "redirect with"
https://laravel.com/docs/5.2/responses#redirecting-with-flashed-session-data
Additional to #Harry Bosh answer,
In Laravel there an issue when Session::save() happen inside the middleware,
this make _flash session gone after redirection happen
this can be fix by using alternative :
// replace your Session::save() to this
session(['yoursessionvar' => $examplevar]); // this will save laravel session
Related
How do I solve my problem ?
Let me tell that how can i change language in laravel web page
List item
Route::get('/{lang?}', function($lang = null){
App::setLocale($lang);
return view('frontend.home');
});
This code will work only for the current request, so when you return the view, it's a new request.
So what you have to do is to persist the language, for each request, so we'll use middleware.
First of all, create a middleware, to check the which language is set, as follows,
public function handle(Request $request, Closure $next)
{
if (session()->has("lang")) {
App::setLocale(session()->get("lang"));
}
return $next($request);
}
What this code will do is, check if the session has the lang_code exists, so it will set it.
After that, you need to add this middleware to your $middlewareGroups, inside app\Http\Kernel.php, as follows :
<?php
'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\Language::class, # This is the line we will add
],
Then finally we'll tweak a little bit your function to become like this :
Route::get('/{lang?}', function($lang = null){
App::setLocale($lang);
session()->put('lang', $lang);
return view('frontend.home');
});
Like this, within each request, the middleware will verify the language, and set it.
My system is built using Vue and Laravel. My requirement is to send a one-time password to the User on each login. Hence, I have created a custom login API controller. I can create a Passport token and send it back to the User. However, I also want Laravel to persist the user session, but, that's not happening. Below is my code for reference:
Api\LoginController.php
public function login(Request $request)
{
$data = $request->all();
if (auth()->attempt($data)) {
$token = auth()->user()
->createToken(config('app.passport_token_key'))->accessToken;
$user = User::whereEmail($data['email'])->first();
// It is not persisting. When I redirect the user to the next page,
// it doesn't pass the auth middleware.
auth()->login($user);
if ($this->sendVerificationCode($user)) { // Send One Time Password
return [
'token' => $token,
];
}
}
return ['error' => true, 'message' => 'Unauthorized'];
}
web.php (route file)
use App\Http\Controllers\HomeController;
Route::middleware(['auth'])->group(function () {
Route::get('/home', [HomeController::class,
'index'])->name('home');
});
Auth::routes();
api.php (route file)
use App\Http\Controllers\Auth\LoginController;
Route::post('login', [LoginController::class, 'login'])
->name('api:login');
I am calling the login API using Vue JS (Axios).
Once the user is logged in (via API), my end goal is that web, and api both guards should know the user session. However, only the api guard can authenticate me (not the web guard).
The problem is, the StartSession middleware is only present in the web routes. Check your app/Http/Kernel.php file, it should be something like this:
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
// NOTE the StartSession Here
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
If you want to use the session, you should add the middleware to your login route.
Inside the $routeMiddleware array inside app/Http/Kernel.php add:
'session.start' => \Illuminate\Session\Middleware\StartSession::class
Then add the middleware to the logi route in your routes/api.php file:
Route::post('login', [\App\Http\Controllers\Api\LoginController::class, 'login'])
->name('api:login')
->middleware('session.start');
When the user logged in for the first time via email and password given to the user manually. They need to be forced to enter a new password (password and confirmed password - only two fields).
I have created a middleware:
class FirstTimeLogin
{
public function handle($request, Closure $next)
{
if ($request->user()->first_time_login) {
return redirect()->route('setup-password');
}
return $next($request);
}
}
In Kernel.php I have added \App\Http\Middleware\FirstTimeLogin::class in the $middlewareGroups array: eg:
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\FirstTimeLogin::class
]
];
web.php route look like this:
Route::group(['middleware' => ['auth']], function () {
Route::get('/home', 'HomeController#index')->name('home');
Route::get('/password/setup-password', 'Auth\SetupPasswordController#resetPasswordFirstTime')->name('setup-password');
Route::post('/password/setup-password', 'Auth\SetupPasswordController#updatePassword');
});
Problem is it keep redirecting many times on the browser, which caused ERR_TOO_MANY_REDIRECTS error on the browser. How to fix this?
You just applied the new middleware to all the web routes, so when user is redirected to ->route('setup-password') middleware kicks in again so you have infinite redirects
One way to fix this is to create an exclusion for those 2 routes that are used for password setup
Make sure you give second route a name, something like setup-password-post
And then change your middleware for code:
if ($request->user()->first_time_login) {
if (!in_array(Route::currentRouteName(), ['setup-password', 'setup-password-post'])) {
return redirect()->route('setup-password');
}
}
You'll need to put a check in to make sure the current route isn't setup-password.
Try changing your if statement to something like:
if ($request->user()->first_time_login && !$request->is('setup-password')) {
i login to application dashboard successfully and have no problem in authentication but after that when i click on another link in the page, again return me to login page. by mean for every request take me to login page!?
please help
my web routes:
Auth::routes();
Route::group([ 'middleware' => 'auth'] , function() {
Route::get('admin', function() {
return view('master');
});
Route::get('admin/categories','CategoryController#index')->name('categories.index');
Route::get('admin/categories/create','CategoryController#create')->name('categories.create');
Route::post('admin/categories/store','CategoryController#store')->name('categories.store');
Route::get('admin/categories/edit/{id}','CategoryController#edit')->name('categories.edit');
Route::post('admin/categories/update/{id}','CategoryController#update')->name('categories.update');
Route::delete('admin/categories/delete/{id}','CategoryController#destroy')->name('categories.destroy');
});
As far as the details you've provided, I can already see that you have not added web middleware group to your route group.
The web middleware group is responsible for things such as encrypting cookies, verifying CSRF token and starting session.
In app/Http/Kernel.php:
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,
],
];
So, most likely the issue is that you haven't started a session, therefore logging in only works for one request.
Apply the web middleware group to your route group and it should solve the issue:
Route::group(['middleware' => ['web', 'auth']], function () {
Route::get('admin', function () {
return view('master');
});
Route::get('admin/categories', 'CategoryController#index')->name('categories.index');
Route::get('admin/categories/create', 'CategoryController#create')->name('categories.create');
Route::post('admin/categories/store', 'CategoryController#store')->name('categories.store');
Route::get('admin/categories/edit/{id}', 'CategoryController#edit')->name('categories.edit');
Route::post('admin/categories/update/{id}', 'CategoryController#update')->name('categories.update');
Route::delete('admin/categories/delete/{id}', 'CategoryController#destroy')->name('categories.destroy');
});
I am trying to implement flash messaging using sessions but am unable to do so.
In my controller I have:
public function store(Request $request) {
session()->flash('donald', 'duck');
session()->put('mickey', 'mouse');
return redirect()->action('CustomerController#index')->with('bugs', 'bunny');
}
But when I check the session variables in the view, I can only see the values from session()->put('mickey', 'mouse').
Session:
{"_token":"F6DoffOFb17B36eEJQruxvPe0ra1CbyJiaooDn3F","_previous":{"url":"http:\/\/localhost\/customers\/create"},"flash":{"old":[],"new":[]},"mickey":"mouse"}
A lot of people encountered this problem by not having the relevant routes inside the web middleware. I made sure to do this as well but it still wouldn't work.
In routes.php:
Route::group(['middleware' => ['web']], function () {
Route::get('/', function () {
return view('welcome');
});
Route::get('/customers', 'CustomerController#index');
Route::get('/customers/create', 'CustomerController#create');
Route::post('/customers', 'CustomerController#store');
});
In Kernel.php:
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',
],
];
Can anyone let me know what I could be doing wrong here? Thanks!
Fixed the issue by replacing
Route::group(['middleware' => ['web']], function () {
...
});
with
Route::group(['middlewareGroups' => ['web']], function () {
...
});
No idea why this works though when all the documentation suggests that we use ['middleware' => ['web']]
This is more than likely because of a change that was made to the Laravel framework (v5.2.27) that all routes by default are part of the "web" middleware, so assigning it again in your routes.php file ends up assigning it twice.
The solution is either to remove the "web" middleware from your routes OR remove the automatic assignment from the RouteServiceProvider.
Before the Laravel update:
// RouteServiceProvider.php
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
});
After the Laravel update:
// RouteServiceProvider.php
$router->group([
'namespace' => $this->namespace, 'middleware' => 'web',
], function ($router) {
require app_path('Http/routes.php');
});
Notice how the new update automatically applies the "web" middleware to all routes. Simply remove it here if you wish to continue using Laravel 5.2 as you have before (manually assigning "web" middleware in your routes.php).
Build your Session flash info by using this code:
<?php
Session::flash("Donald", "Duck")
// Or in your code style.
$request->session()->flash("Donald", "Duck")
?>
Check it in your view with:
#if(Session::has("Donald")
{{Session::get("Donald")}}
#endif
You forget to use $request :)
In Controller:
use Session,Redirect;
public function store(Request $request)
{
Session::flash('donald', 'duck');
Session::put('mickey', 'mouse');
return Redirect::to('/customers')->with('bugs', 'bunny');
}
In 'view' check the data is getting or not:
<?php
print_r($bugs);die;
?>
Good Luck :)
I use the following:
In my controller:
public function xyz(){
// code
// This
return redirect()->action('homeController#index')->with('success', 'Check! Everything done!');
// Or this
return redirect('/index')->with('success', 'Check! Everything done!');
}
In my view:
#if(session('success'))
{{ session('success') }}
#endif
Nothing else. The web-middleware is assigned to every route.
I dont know why but on Windows you need changes in your routes: middleware to middlewareGroups, like that:
So, in your app\Kernel.php, you need put the StartSession at first on array of middleware group web: