"Trying to get property 'headers' of non-object" Middleware\VerifyCsrfToken.php:180 - laravel

I wrote my custom middleware, but when it is executed, the error appears.
Middleware:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\Employee;
class CheckConfirm
{
public function handle($request, Closure $next)
{
if(Auth::check())
{
$id = Auth::id();
$empl = Employee::where('user_id','=', $id)->get();
if($empl->isEmpty())
{
return route('confirm');
}
else
{
dump($empl);
return $next($request);
}
}
else
{
return route('login');
}
}
}
When I try something like this:
if($empl===null)
{
return route('confirm');
}
сondition just doesn't work.
In this case, database queries are executed successfully.
Here is the error page with dump

Your middleware must return a Response object, or $next($request). As written, when not logged in or when $empl is empty, your middleware is just returning a string, not a redirect.
Update your returns to:
return redirect()->route('confirm');
and
return redirect()->route('login');
respectively.

It is very hard to fix, I tried to do it with App\Http\Middleware\VerifyCsrfToken::except, but not work.
My solution to this problem was creating a redirect to another route using App\Exception\Handler::render method.
if ($exception->getMessage() == "Trying to get property 'headers' of non-object") {
return redirect()->route('my.default.page');
}

Replace this line:
$empl = Employee::where('user_id','=', $id)->get();
if($empl->isEmpty()){ ... }
With this:
$empl = Employee::where('user_id', $id)->first();
if($empl){ ... }
Then dd() for each line, see where it fails. There may be an missing csrf token or the user is not logged..

Related

Laravel feature test using middleware

I'm trying to make a feature test for the start page of my Laravel application.
Route:
Route::domain('{subdominio}.'.env("APP_DOMAIN"))->middleware('mapNumserie')->group(function () {
Route::get('/', 'FarmaciaController#show')->middleware('modomtofarmacia')->name('inicio');
})
For some reasons, I use a middleware mapNumserie where I map the subdomain aganist a serial number $idfarmacia in order to use it after in controller:
public function handle($request, Closure $next){
try{
$route = $request->route();
$idfarmacia = \App\Farmacia::where('subdominio', $route->subdominio)->value('numserie');
$route->setParameter('idFarmacia', $idfarmacia);
$route->forgetParameter('subdominio');
}
catch (\Exception $e){
abort(404);
}
return $next($request);
}
In my ModoMtoFarmacia middleware I just check that an app instance is not in maintenance mode or disabled:
public function handle(Request $request, Closure $next){
$farmacia = \App\Farmacia::find($request->idFarmacia);
if($farmacia->inactiva){
abort(404);
}
if(!$farmacia->modomantenimiento){
return $next($request);
}
else{
return response()->view('errors.503')->setStatusCode(503);
}
}
In my controller symply get some data using this $idfarmacia and return a view:
public function show(Request $request, $idfarmacia) {
$data =
//Query...
if($data){
return view('inicio', ['data' => $data]);
}
else{
abort(404);
}
}
With a very simple test method I hope to validate a 200 response :
public function test_example(){
$response = $this->get('http://mysubdomain.domain.prj');
$response->assertStatus(200);
}
But when I run the test I get:
Expected response status code [200] but received 404.
The used URL works correctly in web environment, but the test fails. Where am I wrong?
Finally a found the problem in my phpunit.xml settings, which caused an error in the first query (also in any other), in this case the one found in the MapNumserie middleware:
$idfarmacia = \App\Farmacia::where('subdominio', $route->subdominio)->value('numserie');
I had to set up properly the values of DB_DATABASE and DB_CONNECTION

Laravel 8 Trying to get property 'type' of non-object error

I am trying to make it so I can as admin impersonate users in my app. I get this error
Trying to get property 'type' of non-object
on this line
if($user->type !== 1) //1 for type admin
in someUserController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Auth;
use App\Models\User;
class someUserController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$id = Auth::id();
$user = User::find($id);
//echo '<pre>ID:'.$id.' - '.print_r($user,1); die();
if($user->type !== 1) //1 for type admin
{
echo ' error not admin (nice try!).';
die();
}
}
public function impersonate($id)
{
Auth::logout(); // for end current session
Auth::loginUsingId($id);
return redirect()->to('dashboard');
}
}
route web.php
Route::get('/impersonate/{id}', [someUserController::class, 'impersonate']);
Route::get('dashboard', function () {
$id = \Illuminate\Support\Facades\Auth::id();
$user = \App\Models\User::find($id);
//echo '<pre>'.print_r($user,1); die();
if(!$user->active) return redirect('404-page');
switch($user->type)
{
case 1: return redirect('x-url-dashboard-1'); break;
case 2: return redirect('x-url-dashboard-2'); break;
case 3: return redirect('x-url-dashboard-3'); break;
}
This is the link in my blade file.
Enter as {{$user->name}}
This is happening because User::find($id); is returning null, indicating that there is no user in your database with the nominated id.
In any case, you'll find it easier to use Auth::user() instead, as with your current code you are make two database calls for no real reason.
You're already authenticated so it knows who you are
Don't need to find the user by id, you already have it.
To fix your issue, check that the $id is what you think it should be.
As a follow up to what #Jason explained, you could try something like below:
public function __construct()
{
$this->middleware('auth');
if(Auth::user()->type !== 1)
{
abort(403);
}
}

laravel 6 redirect back to page after login using socialite package [duplicate]

I have a page with a some content on it and a comments section. Comments can only be left by users who are signed in so I have added a login form to the page for users to sign in with (this only shows if they are not already logged in).
The problem I have is that when the user signs in they get redirected back to the home page and not the page they were previously on.
I have not changed the login method from the out of the box set-up.
Can anyone suggest a simple way to set the redirect url. My thoughts are that it would be good to be able to set it in the form.
Solution for laravel 5.3:
In loginController overwrite the showLoginForm() function as this one:
public function showLoginForm()
{
if(!session()->has('url.intended'))
{
session(['url.intended' => url()->previous()]);
}
return view('auth.login');
}
It will set the "url.intended" session variable, that is the one that laravel uses to look for the page which you want to be redirected after the login, with the previous url.
It also checks if the variable has been set, in order to avoid the variable to be set with the login url if the user submit the form with an error.
For Laravel 5.5, following code worked for me by just updating LoginController.php
public function showLoginForm()
{
session(['link' => url()->previous()]);
return view('auth.login');
}
protected function authenticated(Request $request, $user)
{
return redirect(session('link'));
}
Please use redirect()->intended() instead in Laravel 5.1
You can also see more about it here: http://laravel.com/docs/5.1/authentication
For Laravel 5.3
inside App/Http/Controllers/Auth/LoginController
add this line to the __construct() function
$this->redirectTo = url()->previous();
So the full code will be
public function __construct()
{
$this->redirectTo = url()->previous();
$this->middleware('guest', ['except' => 'logout']);
}
It works like a charm for me i'm using laravel 5.3.30
For Laravel 5.4, following code worked for me by just updating LoginController.php
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\URL;
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
Session::put('backUrl', URL::previous());
}
public function redirectTo()
{
return Session::get('backUrl') ? Session::get('backUrl') : $this->redirectTo;
}
The Laravel 5.6, When user insert wrong credentials then login page will reload and session(['link' => url()->previous()]); will take login URL in link variable. So the user will redirect to a login page again or redirect to /home if login success. So to avoid these below code working for me! After that no matter how much time user insert wrong credentials he will redirect after login to exactly where he was before login page.
Update or overwrite public function showLoginForm() in LoginController.
public function showLoginForm()
{
if (session('link')) {
$myPath = session('link');
$loginPath = url('/login');
$previous = url()->previous();
if ($previous = $loginPath) {
session(['link' => $myPath]);
}
else{
session(['link' => $previous]);
}
}
else{
session(['link' => url()->previous()]);
}
return view('auth.login');
}
Also, Update or Overwrite protected function authenticated(Request $request, $user) in LoginController.
protected function authenticated(Request $request, $user)
{
return redirect(session('link'));
}
If you want to redirect always to /home except for those pages with comments, then you should overwrite your redirectTo method in your LoginController:
public function redirectTo()
{
return session('url.intended') ?? $this->redirectTo;
}
On all pages where you want to remain on the site, you should store the url for one request in the session:
public function show(Category $category, Project $project){
// ...
session()->flash('url.intended' , '/' . request()->path());
}
Redirect to login with the current's page url as a query string:
login
In your LoginController check if exists and save the query string in session then redirect to the url after login
public function __construct() {
parent::__construct();
if ( \request()->get( 'redirect_to' ) ) {
session()->put( 'redirect.url', \request()->get( 'redirect_to' ) );
}
$this->middleware( 'guest' )->except( 'logout' );
}
protected function authenticated(Request $request, $user) {
if(session()->has('redirect.url') {
return redirect( session()->get( 'redirect.url' ) );
}
}
Look into laravel cheat sheet
and use:
URL::previous();
to go to the previous page.
Laravel 5
(maybe 6 also, not tested, if someone knows it please update the answer)
add this to LoginController:
protected function redirectTo(){
return url()->previous();
}
Note: if present the field $redirectTo , remove it
in your RedirectIfAuthenticated.php change this code
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect()->intended('/contactus');
}
return $next($request);
}
please notice to :
return redirect()->intended('/contactus');
Inside your template file you can just use:
{{ url()->previous() }}
To redirect from the controller you should use
return redirect()->back();
or Just
return back();
use Illuminate\Support\Facades\Redirect;
public function Show_Login_Form()
{
$back = Session::put('url_back',url()->previous());
$current = url()->current();
if(Session::get('user_id'))
{
if ($back == $current) { // don't back Login Form
return Redirect::to('home');
}
elseif (Session::has('url_back')) {
return Redirect::to('home');
}
else{
return redirect()->back();
}
}
else{
if ($back == $current) {
return Redirect::to('home');
}
else{
Session::put('url_back',url()->previous());
}
return view('account.customer-account.login');
}
}
public function signin_user(Request $request) // Login post
{
$username = $request->input_username_login;
$password = md5($request->input_password_login);
$result = DB::table('tbl_user')
->where([['user_email',$username],['user_password',$password]])
->orWhere([['user_phone',$username],['user_password',$password]])
->first();
if($result){
Session::put('user_id', $result->user_id );
Session::put('user_name', $result->user_name);
Session::put('user_username', $result->user_username);
Session::put('user_avatar', $result->user_avatar);
return Redirect::to(Session::get('url_back')); // Back page after login
} else {
Session::put('message_box', 'Error !!!');
return redirect()->back();
}
}
You can use redirect back with Laravel 5:
<?php namespace App\Http\Controllers;
use Redirect;
class SomeController extends Controller {
public function some_method() {
return Redirect::back()
}
}
Use Thss
return Redirect::back('back-url')

return a json error in middleware?

I'm building an app and I'm using laravel5 as webAPI.
When the webAPI is in Maintenance Mode, I want to return a json error to app and I will get the status code in app to show a suitable message.
I rewrite the laravel CheckForMaintenanceMode for somereason and registed it in Kernel.
I write
if ($this->app->isDownForMaintenance()) {
$ip = $request->getClientIp();
$allowIp = "111.222.333.444";
if ($allowIp != $ip) {
return response()->json(['error' => "Maintenance!!"], 503);
}
}
return $next($request);
But I can get NOTHING in app side.I cannot get the message, the satus....
I writh the same code like return response()->json(['error' => "errormessage"], 422); in controller and I can get the message.status.. in app but I cannot do the same thing in a middleware.
why? how to do it?
This worked:
if ($this->app->isDownForMaintenance()) {
$ip = $request->getClientIp();
$allowIp = "111.222.333.444";
if ($allowIp != $ip) {
return response(['Maintenance'], 503);
}
}
return $next($request);
And not register the middleware in Kernel global HTTP middleware but put it in the route(api.php),like:
Route::group(['middleware' => 'maintenance'], function(){******}
I really donot know why but this worked for me.
Full example
public function handle($request, Closure $next)
{
if($request->token == "mytoken")
return $next($request);
else return response(['Token mismatch'],403);
}
Explanation
The response of a middleware
must be an instance of Symfony\Component\HttpFoundation\Response
so, for return a json, you have to do this
return response(['Token mismatch'],403);
The middleware must be registered in Kernel.php
The cleaner way to do it is to extend the
Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode class
and change it as per our needs and update the App\Http\Kernel.php like so..
App\Http\CustomMaintanceMiddleware.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
class CustomMaintanceMiddleware extends CheckForMaintenanceMode
{
public function handle($request, Closure $next)
{
if ($this->app->isDownForMaintenance()) {
return response(['Maintenance'], 503);
}
return $next($request);
}
}
Kernel.php
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class
];
TO
protected $middleware = [
\App\Http\CustomMaintanceMiddleware::class
];

The localhost page isn’t working in laravel

Here is my controller code:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Route;
use Input;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\models\Designation;
use Validator;
class Cdesigination extends Controller
{
public $flight;
public function __construct(){
$this->flight = new Designation;
}
public function index(request $request)
{
$this->flight->name = $request->name;
$this->flight->detail = $request->detail;
$this->flight->token_key = $request->_token;
$data=$this->flight->save();
if($data){
return Redirect::to('posts')->withInput()->with('success', 'Inserted Successfully.');
}
else {
return Redirect::to('posts')->withInput()->with('success', 'Not inserted Successfully.');
}
return view('designation');
}
}
Here is route code:
Route::get('/posts', 'Cdesigination#index');
Where is trouble and how to solve it?
I think redirect keyword create trouble because when i raze the redirect:: to keyword then working fine.
Its not the Redirect. You are using withInput() and with('success', 'Inserted Successfully.'). Use any one. You might want to erase withInput() and try. Also do you not get laravel errors displayed on your page ?
It seems you're going to /posts which uses Cdesigination#index action. And this action always redirects to the same page, to itself. And it will be redirected to itself again and again and again.
So view('designation') will never be loaded:
if ($data) {
// If $data is true, redirect
return Redirect::to('posts')->withInput()->with('success', 'Inserted Successfully.');
} else {
// If not, redirect too
return Redirect::to('posts')->withInput()->with('success', 'Not inserted Successfully.');
}
// Any code here will never be executed
I'm not sure what are you trying to accomplish, but if you want to load designation view with messages, you should do something like this:
if ($data) {
// If $data is true, redirect
return view('designation')->withInput()->with('success', 'Inserted Successfully.');
} else {
// If not, redirect too
return view('designation')->withInput()->with('success', 'Not inserted Successfully.');
}

Resources