Laravel Middleware Error - Call to a member function isBasic() on null - php

I want to check user type when they log in and apply function
In my middleware, I have this code
public function handle($request, Closure $next)
{
$user = Auth::user();
if ($user->isBasic()) {
$previous_session = $user->session_id;
if ($previous_session) {
\Session::getHandler()->destroy($previous_session);
}
Auth::user()->session_id = \Session::getId();
Auth::user()->save();
return redirect(route('home'));
}
return $next($request);
}
In my User model, I have this
public function isBasic()
{
return $this->role=='basic';
}
I have already registered the middleware in Kernel
'basic' => \App\Http\Middleware\CheckSession::class,
And I passed it to my LoginController like this
public function __construct()
{
$this->middleware('basic');
}
But when it tried to visit the login controller, it says
Call to a member function isBasic() on null
I am a beginner in Laravel and I don't know what to do

This seems like a good candidate for the authenticated method of the LoginController which gets called after a user has logged in.
use Illuminate\Http\Request;
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
if ($user->isBasic()) {
$previous_session = $user->session_id;
if ($previous_session) {
$request->session()->getHandler()->destroy($previous_session);
}
$user->session_id = $requset->session()->getId();
$user->save();
// do these specific users need to be redirected to somewhere special?
return redirect()->route('home');
}
}
You could even listen for the Auth events if you wanted to, as long as its not a queued listener.

you should use Auth::check() to determine if user is authenticated or not
in your middleware, you are doing
$user = Auth::user();
if ($user->isBasic()) {...}
In this part, if the user is not authenticated then the $user will have null value
you will have to check if the user is authenticated or not.
Eg:
public function handle($request, Closure $next)
{
if(Auth::check()) { //check if the user is logged in or not
$user = Auth::user();
if ($user->isBasic()) {
$previous_session = $user->session_id;
if ($previous_session) {
\Session::getHandler()->destroy($previous_session);
}
Auth::user()->session_id = \Session::getId();
Auth::user()->save();
return redirect(route('home'));
}
}
return $next($request);
}

Related

How to restrict a user to only see their own profile

I have a view (resources/view/front/auth/profile.blade.php) and my route in file web.php is:
Route::get('/profile/{user}','UserController#edit')
->name('profile')
->middleware('profilecheck');
My problem is that when a user logs in and gets redirected to their own profile page (http://exmaple.com/profile/2), he/she can change the URL to http://exmaple.com/profile/3 and see other users' profile.
I want to use a middleware to check authenticated users id with URL parameter {user}. The $user->id will passed to the {user}, but I have no idea how.
Middleware UserProfile.php:
<?php
namespace App\Http\Middleware;
use App\User;
use Closure;
class UserProfile
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
// $request->user()->id
// Auth::user()->id
return $next($request);
}
}
You can protect the route simply by removing the user id from the URL, but getting it through the authentication session instead.
So, your route signature should goes from:
Route::get('/profile/{user}', 'UserController#edit')->name('profile');
To this:
Route::get('/profile', 'UserController#edit')->name('profile');
So, in your controller, instead of getting the user id from the request:
public function edit(Request $request)
{
$user = User::findOrFail($request->id);
// ...
}
You could get the logged-in User through the Auth facade:
use Illuminate\Support\Facades\Auth;
public function edit(Request $request)
{
$user = Auth::user();
// ...
}
or just the auth() helper:
public function edit(Request $request)
{
$user = auth()->user();
// ...
}
This way, you are masking the URL to avoid a malicious user of doing things that he/she shouldn't.
You need to do something like this.
Your route
Route::get('/profile', [
'uses' => 'UserController#profile',
'middleware' => 'profilecheck'
]);
Your middleware
class CheckUserMiddleware
{
public function handle($request, Closure $next)
{
if(!auth()->user()) {
return redirect()->route('login');
}
return $next($request);
}
}
// Controller
public function index()
{
if (Auth::check() && Auth::user()->role->id == 2) {
return view('author.setting.settings');
} else {
Toastr::info('you are not authorized to access', 'Info');
return redirect()->route('login');
}
}
// Route
Route::group(['as'=>'user.','prefix'=>'user','namespace'=>'Author','middleware'=>['auth','user']], function (){
Route::get('/setting','SettingsController#index')->name('settings.settings');
});

Laravel 5.6 - Auth::check() Failing

I used the laravel spatie backup in my system, and all my functions such as creating a new backup, deleting, and downloading are working locally. I tried to deploy my website on a free hosting, everything seems to work except the delete and download function. Upon investigating, I have seen that it fails because of the Middleware I have created for the download/delete route. Here's my StaffMiddleware where only accounts with the staff role can access it.
Middleware
public function handle($request, Closure $next)
{
if(Auth::check())
{
if(Auth::user()->role == 'staff')
{
return $next($request);
}
else
{
return redirect('/');
}
}
else
{
return redirect('/');
}
}
Routes
Route::get('backup/create', 'Admin\BackupController#create');
Route::get('backup/download/{file_name}', 'Admin\BackupController#download');
Route::get('backup/delete/{file_name}', 'Admin\BackupController#delete');
When I try to access the download function, it redirects to the homepage since the Auth::check() line fails in my middleware. Note that I am logged in and authenticated while accessing the download function. This only happens in the live server, but all of the code works locally. Can you please help me on this one? Thanks!
can you try this
public function handle($request, Closure $next)
{
$user = Auth::user();
//dd($user); //debug if didn't work
if($user && $user->role == 'staff') // if your role is coming from relation then try `$user->role->name == 'staff'`
{
return $next($request);
}
return redirect('/');
}
I think you have to get the user from the request
public function handle($request, Closure $next)
{
if ($request->user() && $request->user()->role == 'staff')) {
return $next($request);
}
return redirect('/');
}
You can try this:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminMiddleware {
/**
* 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)->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect('admin/login');
}
}else{
if( \Auth::user()->role =="admin" ){
return $next($request);
}
}
return redirect("admin/login");
}
}

Adding values to request array in Laravel middleware is a good practice?

I have an authentication middle ware to check the validity of the passed api key. I fetch user id from the database store it to the request array so that the requesting page will get the userid.
public function handle($request, Closure $next) {
$key = $request->get('key');
$user = User::where('token', '=' ,$key)->first();
if($user != null){
$request->request->add(['middlewareUserID' => $user->id]);
return $next($request);
}
else {
return response(401);
}
}
Is it a good practice?
I would say this is not necessary in such case.
I would use code similar to this:
use Illuminate\Contracts\Auth\Guard;
class YourMiddleware
{
protected $guard;
public function __construct(Guard $guard)
{
$this->guard = $guard;
}
public function handle($request, Closure $next) {
$key = $request->get('key');
$user = User::where('token', '=' ,$key)->first();
if(!$user){
return response(401);
}
$this->guard->setUser($user);
return $next($request);
}
}
so when there is user for given token you can authenticate user in line $this->guard->setUser($user); and when the token is invalid you return return response(401);
I don't see any need to set this user id to request as you showed.

Multiple AdminMiddleware Ambiguity

I have multiple admin system: one is super admin and the other is normal admin, distinguished by is_admin attribute in users table.
And these two middlewares:
SuperAdminMiddleware.php
public function handle($request, Closure $next, $guard = null)
{
if(Auth::check())
{
if($request->user()->is_admin==1)
{
return $next($request);
}
return redirect('/login');
}
else
{
return redirect('/login');
}
}
and, NormalAdminMiddleware.php
public function handle($request, Closure $next, $guard = null)
{
if(Auth::check())
{
if($request->user()->is_admin==2)
{
return $next($request);
}
return redirect('/login');
}
else
{
return redirect('/login');
}
}
and in loginController:
protected function authenticated()
{
if (auth()->user()->is_admin==1) {
return redirect('/super-admin');
}
else if(auth()->user()->is_admin==2){
return redirect('/normal-admin');
}
else {
return redirect('/home');
}
}
Now, Delete and Read should be designed in such a way that super admin can delete and see all users details, while normal admin can only see their city's user.
id name city is_admin
1 Non Maety 1
3 Pom Lorey 2
4 Rom Lorey 0
2 Yer Easter 0
Non should be able to see all. while Pom should see only id 3 and 4.
If i put show and delete routes under SuperAdminMiddleware, Normal Admin couldnot see their city's records.
Route::group(['middleware' => ['App\Http\Middleware\SuperAdminMiddleware']], function () {
Route::get('/show/{id}', 'MyController#show');
Route::post('/delete', 'MyController#delete');
});
And if i put these routes under both SuperAdminMiddleware and NormalAddminMiddleware. NormalAdminMiddleware can also see other city's records.
Route::group(['middleware' => ['App\Http\Middleware\NormalAdminMiddleware']], function () {
Route::get('/show/{id}', 'MyController#show');
Route::post('/delete', 'MyController#delete');
});
How do i overcome this situation?
You can solve it with a policy:
class UserPolicy
{
/**
* Determine if the given user can be viewed by the user.
*
* #param \App\User $user
* #param \App\User $account
* #return bool
*/
public function view(User $user, User $account)
{
switch($user->is_admin) {
case 1:
return true;
case 2:
return $user->city == $account->city;
default:
return 0;
}
}
/**
* Determine if the given user can be updated by the user.
*
* #param \App\User $user
* #param \App\User $account
* #return bool
*/
public function update(User $user, User $account)
{
switch($user->is_admin) {
case 1:
return true;
case 2:
return $user->city == $account->city;
default:
return 0;
}
}
}
User would be the authenticated user model, account would be the user model that should be viewed.
After you registered your policy (https://laravel.com/docs/5.4/authorization#registering-policies) you can call it in the function of your controller like:
public function show(User $user) {
$this->can('view', $user);
}
I don't understand your purpose clearly by reading the question. If you put your methods under SuperAdminMiddleware, normal admin should be rejected and redirect to '/login'. If you want to control the operation of admin, I think middleware can't solve the problem. As the previous answer, when operate the data of database, judge whether he is superAdmin or not.

How to restrict user login in Laravel if email is not verified

I am using 'jrean' package in Laravel for verifying emails of registered users.
https://packagist.org/packages/jrean/laravel-user-verification
The problem I am facing currently is even if the user is registered how can I restrict his access until the email is not verified. I have followed all the steps given in the package tutorial for implementing registration. But they don't have any steps listed for restricting login access. Any ideas?
You can overwrite your login method. In L5.2 and asumming you have a verified field in your users table which is boolean you can do something like:
In your app/Http/Controllers/Auth/AuthController.php add something like:
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Support\Facades\Auth;
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$this->validateLogin($request);
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
if (Auth::user()->verified == true) { // This is the most important part for you
return $this->handleUserWasAuthenticated($request, $throttles);
} else {
Auth::logout();
return $this->sendFailedLoginResponse($request, "Some message here");
}
}
if ($throttles && !$lockedOut) {
$this->incrementLoginAttempts($request);
}
return $this->sendFailedLoginResponse($request);
}
You also need to add the verified field in your User eloquent model in order to use it in your modified login method.
Hope it helps!
You can create simple middleware and check if email is verified there. For example, if verified is boolean in users table, you can do this:
public function handle($request, Closure $next)
{
return auth()->user() && auth()->user()->verified
? $next($request); // Will pass user.
: redirect('/'); // Will redirect user to the main page if email is not verified.
}
}
Do not forget to register middleware and apply it to route(s) you want to protect.
Apply verified middleware to the URL and it will prevent visiting the URL until user verifies their email. Route::get('/users', 'UserController#index')->name('users')->middleware('verified');
Use this:
public function __construct() {
$user = Auth::guard('api')->user();
if(!$user->hasVerifiedEmail()) {
abort($this->respondUnauthorized(trans('response.email_not_verified')));
}
}
hasVerifiedEmail() Determine if the user has verified their email address.
It will check for all routes/methods in your controller
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/');
}
return $next($request);
}
public function handle(Request $request, Closure $next)
{
if (\App\Models\User::where('email', $request->input('email'))->first()->email_verified_at != null) {
return $next($request);
} else {
return redirect('/login')->with('email_not_verified', 'Email not verified, Please check your email to validate it');
}
}

Categories