Laravel Custom Exception is giving me Undefined property::$headers - laravel

I am working on an exception right now in laravel giving a weird behavior that I have not seen before and can't seem to find much information about. I am getting this error message Undefined property: App\Exceptions\UserNotApproved::$headers. Not sure whats going.
<?php
namespace App\Exceptions;
use Exception;
class UserNotApproved extends Exception
{
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* #param \Exception $exception
* #return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}
/**
* Render the exception into an HTTP response.
*
* #param \Illuminate\Http\Request
* #return \Illuminate\Http\Response
*/
public function render($request)
{
return response()->view('errors.not_approved',['exception'=>$this],403);
}
}
/var/www/epg_intranet/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php
$response->headers->setCookie at line 159
<?php
namespace App\Http\Middleware;
use App\Exceptions\UserNotApproved;
use App\User;
use Closure;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class VerifyUserApproval
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::check() && Auth::user()->user_type == null){
return new UserNotApproved();
}
return $next($request);
}
}
I am calling this in a middleware. W0uld that have anything to due with the error?

public function handle($request, Closure $next)
{
if (Auth::check() && Auth::user()->user_type == null){
return new UserNotApproved();
}
return $next($request);
}
A middleware is supposed to take in a response, look at it and do something, and then return a response so that the next middleware can do it's job as well. Returning a UserNotApproved class is throwing this error since the next middleware is not receiving a request object.
You could do something like this:
public function handle($request, Closure $next) {
if (Auth::check() && Auth::user()->user_type == null) {
abort(400, 'User not approved.');
}
return $next($request);
}
You may be able to do this as well
public function handle($request, Closure $next) {
if (Auth::check() && Auth::user()->user_type == null) {
throw new UserNotApproved();
}
return $next($request);
}

Related

Can I use dynamic model on middleware?

I have 2 routes that requires a person to be tagged to access the discussions.
http://localhost:8000/api/fieldReports/{fieldReport}/discussions
http://localhost:8000/api/agendas/{agenda}/discussions
Currently, I have created this middleware, but instead of pointing right to a specific model, and duplicate it for each model with the exact same functionality, I want it to be more reusable.
Middleware\ForbidUntaggedUser.php
class ForbidUntaggedUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$user = $request->user();
$report = $request->report; // <-- I hardcoded the model, I want this to be dynamic
// The `taggedUsers` remains the same (identical) for each model that has tagging system on it.
if (!$report || !$report->taggedUsers->contains($user->id)) {
return response()->json('Your action is unauthorized.', 403);
}
return $next($request);
}
}
I've tried to use Policy but it doesn't work, so I think I need a middleware for this.
Policies\FieldReportDiscussionPolicy.php
class FieldReportDiscussionPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\Models\User $user
* #return mixed
*/
public function viewAny(User $user, FieldReport $fieldReport)
{
return $user->can('view any fieldReportDiscussion')
&& $fieldReport->taggedUsers->contains($user->id);
}
... // and so on..
}
Controllers\FieldReportDiscussionController.php
class FieldReportDiscussionController extends Controller
{
protected $model;
/**
* Create new instance.
*
* #return void
*/
public function __construct()
{
$this->authorizeResource(
FieldReportDiscussion::class,
['fieldReportDiscussion', 'fieldReport'] // This gave me error "Array to string conversion"
);
$this->model = new FieldReportDiscussion;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(FieldReport $fieldReport)
{
$discussions = $this->model->registries($fieldReport)->paginate(100);
return response()->json($discussions);
}
}
I need the dependency injection on the controller because the route is nested with each model as the parent, like this one..
routes\api.php
Route::apiResource('fieldReports', FieldReportController::class);
Route::apiResource('fieldReports.discussions', FieldReportDiscussionController::class)->except(['update'])->parameter('discussions', 'fieldReportDiscussion');
So, what's the solution for this? Can I make it dynamic (the first request object)?
I think you're on the right track with using middleware, although you'll need some conditional checks, something along the lines like:
class ForbidUntaggedUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$instance = null;
if ($request->report !== null) {
$instance = $request->report;
} else if ($request->agenda !== null) {
$instance = $request->agenda;
}
if (!$instance || !$instance->taggedUsers->contains(auth()->id())) {
return response()->json('Your action is unauthorized.', 403);
}
return $next($request);
}
}
If you have named correctly your params in your controller i.e. in a resoruce controller
<?php
namespace App\Http\Controllers;
use App\Models\Agenda;
class AgendaController extends Controller
{
public function show(Agenda $agenda)
{
....
}
}
The first parameter of your request will be the named model, so you can get the model with the getModel() function, if you are not sure, you can search it with findModel() function.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
class MyMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$model = $this->getModel($request);
$tryGetModel = $this->findModel($request);
}
private function getModel(Request $request) : Model|null
{
$modelParameterName = $request->route()->parameterNames()[0];
return $request->$modelParameterName ?? null;
}
private function findModel(Request $request) : Model|null
{
foreach($request->route()->parameters() as $param)
{
if($param instanceof Model)
return $param;
}
return null;
}
}

Can't access user object

I am trying to handle roles in my application but I have a problem: when I clear cache or logout from the app and log in again I want to be redirected to the login but it sends me the following error
Trying to get property 'rol' of non-object.
<?php
namespace App\Http\Middleware;
use Closure;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (\Auth::user()->rol == 'Admin') {
return $next($request);
}
return redirect()->guest('login');
}
}
you have to check if user is logged in, and then ask if user have rol
use Illuminate\Support\Facades\Auth;
public function handle($request, Closure $next)
{
if (Auth::check()) {
if (Auth::user()->rol == 'Admin') {
return $next($request);
}
return redirect()->guest('login');
}
return redirect()->guest('login');
}

Auth After Middleware

I wish to authenticate the user after the request with my own middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Auth\Middleware\Authenticate;
class AuthenticateAfter extends Authenticate
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string[] ...$guards
* #return mixed
*
* #throws \Illuminate\Auth\AuthenticationException
*/
public function handle($request, Closure $next, ...$guards)
{
$response = $next($request);
$this->authenticate($request, $guards);
return $response;
}
}
I extend Illuminate\Auth\Middleware\Authenticate and modify the handle method to run as after middleware.
It's then declared in my kernel and on the correct route.
But I always get kicked back to the page I was previously on after logging in.
I want to control the page I go to, so before the middleware kicks in I do:
$request->session()->put('url.intended', 'my-test-url');
But it fails to redirect to this route.
How can I get it to redirect to a custom route?
Try this,
public function handle($request, Closure $next, ...$guards)
{
$response = $next($request);
$this->authenticate($request, $guards);
return redirect('/your_page_path');
}
Just for reference, here what I use to authenticate a user:
public function handle($request, Closure $next)
{
if (auth()->user() && auth()->user()->type != 'admin')
{
return redirect('/unauthorized');
}
return $next($request);
}
Try with: return redirect('view') or return redirect()->to('/route')

Object of class Illuminate\Routing\Redirector could not be converted to string

On my laravel project when, I'm trying to authorize, shows me error exception
"Object of class Illuminate\Routing\Redirector could not be converted to string"
It indicates me to my Middleware Class
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/dashboard');
}
return $next($request); //This row could not be converted to string
}
}
and to this file
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Storage;
class VerifyAppInstalled
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (config('database.transfer_mode') == "1") {
if (password_verify($request->server('SERVER_NAME'), getOption('app_key', true))
&& password_verify(strrev($request->server('SERVER_NAME')), getOption('app_code', true))) {
return redirect('/transfer/restore');
}
return redirect('/transfer/ready');
}
if (config('database.installed') == '%installed%') {
return redirect('/install');
}
if (Storage::exists('images/update')) {
return redirect('/update-progress');
}
\App::setLocale(request()->session()->get('locale', getOption('language')));
return $next($request);
}
}
Please help me what is wrong here?
enter image description here

Controller middleware

I have controller named 'AdminController'
And I have a lot of functions in there. The problem is that I dont want in every function user IF statement just like this:
public function index(Request $request)
{
if(Auth::check() && $request->user()->is_admin())
{
return view('admin.index');
}
else
{
flash()->error('You dont have permissions!');
return redirect('home');
}
}
How can I make it more simple with middleware so I could make everything work without using IF statement in every function ?
Create a middleware
php artisan make:middleware IsAdmin
Customize app/Http/Middleware/IsAdmin.php
<?php
namespace App\Http\Middleware;
use Auth;
use Closure;
class IsAdmin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(Auth::check() && $request->user()->is_admin())
{
return $next($request);
}
flash()->error('You dont have permissions!');
return redirect('home');
}
}
Finally register and use the middleware

Resources