I have a problem when I want to pass data to the view via the middleware to count the number of users. when not using middleware, variable from controller get to the view.
my HomeController.php
public function index()
{
$count = User::count();
return view('admin.Dashboard', compact($count);
}
my Middleware
public function handle(Request $request, Closure $next)
{
if ($request->user() && $request->user()->role == 'admin') {
return response()->view('admin.Dashboard');
} else {
return response()->view('member.dashboard');
}
return $next($request);
}
the $count variable if using middleware in route not passed to the view
my web.php
Auth::routes(['verify' => true]);
Route::get('/dashboard', 'HomeController#index')->middleware('verified', 'cekrole')->name('home');
In your middleware you are returning response (a view), so
return $next($request);
will never be executed, so neither will your controller.
User call /dashboard > Your middleware is called > if it's an admin you are returning admin.Dashboard, else member.dashboard.
But you never execute code in your Controller.
As a quick fix you could replace your Middleware by :
public function handle(Request $request, Closure $next)
{
if ($request->user() && $request->user()->role == 'admin') {
$count = User::count();
return view('admin.Dashboard', compact('count'));
}
return response()->view('member.dashboard');
}
or make those test (admin/not admin) in your controller
Related
I'm new to laravel I have created middleware for my each role but when I add it to my route it won't work.
If I add single middleware to my route it works fine but when I add second and third one It will not work.
It won't shows the route to authorized user it redirect it to home,
My User Model:
public function IsAdmin()
{
if($this->role_id =='1')
{
return true;
}
else
{
return false;
}
}
public function IsManager()
{
if($this->role_id =='2')
{
return true;
}
else
{
return false;
}
}
public function IsUser()
{
if($this->role_id =='3')
{
return true;
}
else
{
return false;
}
}
My Kernal:
'IsAdmin' => \App\Http\Middleware\IsAdmin::class,
'IsManager' => \App\Http\Middleware\IsManager::class,
'IsUser' => \App\Http\Middleware\IsUser::class,
My IsAdmin Middlewares:
public function handle($request, Closure $next)
{
$user =Auth::User();
if(!$user->IsAdmin())
{
return redirect('stock');
}
return $next($request);
}
My IsManager
public function handle($request, Closure $next)
{
$user =Auth::User();
if(!$user->IsManager())
{
return redirect('stock');
}
return $next($request);
}
and IsUser
public function handle($request, Closure $next)
{
$user =Auth::User();
if(!$user->IsUser())
{
return redirect('stock');
}
return $next($request);
}
and finally my Route
Route::get('approv',['middleware'=>['IsManager','IsAdmin'],function(){
return view('approv');
}]);
This will not work as you'd expect. All middleware need to pass in order for the request to be processed which means that your user will need to be both a manager and an admin at the same time which based on your setup is impossible.
You can get around this (kind of) by making a different kind of middleware:
Kernel:
'roles' => \App\Http\Middleware\Roles::class,
And the Roles middleware:
class Roles {
private function checkRole($role) {
switch ($role) {
case 'user': return \Auth::user()->IsUser();
case 'manager': return \Auth::user()->IsManager();
case 'admin': return \Auth::user()->IsAdmin();
}
return false;
}
public function handle($request, Closure $next, ...$roles)
{
foreach ($roles as $role) {
if ($this->checkRole($role)) {
//At least one role passes
return $next($request);
}
}
//All checks failed so user does not have any of the required roles
return redirect('stock');
}
}
Then to use this you simply do:
Route::get('approv',['middleware'=>['roles:manager,admin'],function(){
return view('approv');
}]);
This works because Laravel Middleware support parameters. You can pass parameters as a comma separated list of strings where you declare the middleware. In this case this was done as roles:manager,admin
Laravel will then send these parameters as additional parameters in the handle method. These can be accessed using PHPs syntax for variadic arguments. In this particular case it's by using the array spread operator. This is documented as an example in the function arguments section of the PHP manual.
Note that this is actually equivalent to saying :
public function handle($request, Closure $next, $role1=null, $role2=null, $role3=null)
but using the spread operator is much more convenient since ...$roles would be an array which contains only the roles that were passed in the middleware.
In my application I can mark a user as blocked. After a blocked mark he can't do anything.
My solution was to check the status in every construct controller and if the authenticated user is marked as blocked he will redirect to the view.
But my solution isn't very good because i have dublicated code and i have to check for the actual route.
Here is my code:
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next)
{
$this->user= Auth::user();
if(strcmp(Route::currentRouteName(), 'user.password.show') != 0)
{
if(strcmp(Route::currentRouteName(), 'user.password.set') != 0)
{
if(strcmp(Route::currentRouteName(), 'user.blocked.show') != 0)
{
if($this->user->status == Userstatus::where('type', 'passwordSetFalse')->first()->id)
{
Session::flash('error', 'Bitte setzen Sie ihr Passwort!');
return Redirect::route('user.password.show');
}
else
{
return $next($request);
}
}else
{
return $next($request);
}
}
else
{
return $next($request);
}
}
else
{
return $next($request);
}
});
}
I search a solution where i put the code once and i can use it for all my controller but i have no idea where the code can be written in.
Many thanks for your help
Take a look at Laravel Middlewares. Define a middleware that checks for the user status before passing the request to the controllers, than register your middleware in app/Http/Kernel.php.
<?php
namespace App\Http\Middlewares;
class UserBlockedMiddleware
{
public function handle($request, $next)
{
$user = \Auth::user();
if($user->status == 'blocked') abort(403);
return $next($request);
}
}
To learn more on how to register a global middleware check this section in Laravel docs.
You need to read about Protecting Routes
You can attach auth middleware to routes you want to protect, or directly in the __construct of your controller
Laravel ships with an auth middleware, which is defined at Illuminate\Auth\Middleware\Authenticate
If you want your own Auth middleware you can type the following
php artisan make:middleware MyOwnAuth
Also you can actually reduce the code like that
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
$this->user = Auth::user();
if (
strcmp(Route::currentRouteName(), 'user.password.show') != 0
&& strcmp(Route::currentRouteName(), 'user.password.set') != 0
&& strcmp(Route::currentRouteName(), 'user.blocked.show') != 0
&& $this->user->status == Userstatus::where('type', 'passwordSetFalse')->first()->id
) {
Session::flash('error', 'Bitte setzen Sie ihr Passwort!');
return Redirect::route('user.password.show');
};
return $next($request);
});
};
I have a controller like this:
public function __construct()
{
$check = Auth::id();
if ($check->role == '5') {
// allow to run any other controller
} else {
// return view('home')
}
return $check;
}
public function index()
{
return view('admin.home');
}
What I want to do is whenever, AdminController is triggered, run __construct function and check if role == 5, if it is, proceed with the request, else return view. How can that be done?
Edit
public function handle($request, Closure $next)
{
if ($request->role == 2) {
} else {
return view('index');
}
return $next($request);
}
Kernel:
protected $middlewareGroups = [
'admin' => [
\App\Http\Middleware\CheckAdmin::class,
],
];
Route:
Route::group(['middleware' => ['admin']], function () {
Error::
(1/1) FatalThrowableError Call to a member function setCookie() on
null in VerifyCsrfToken.php (line 156)
view() returns a Illuminate\View\View object, instead of a Illuminate\Http\Response. So instead of sending the view. Redirect the user to index route
Try this
public function handle($request, Closure $next)
{
if ($request->role != 2) {
return return redirect()->route('index');
}
return $next($request);
}
This is my route group,
Route::group(['middleware' => 'checkUserLevel'], function () {
// my routes
});
And this is my middleware checkUserLevel,
public function handle($request, Closure $next, $level)
{
$user = Auth::user();
if ($user->level > $level) {
return redirect('testUrl');
}
return $next($request);
}
I want to pass the $level variale to middleware from route group.
Thanks.
You can simply pass multiple arguments into the middleware using a colon. Use it like:
Route::group(['middleware' => 'checkUserLevel:some_value_of_level'], function () {
// my routes
});
Now, you can have this value inside your $level variable.
public function handle($request, Closure $next, $level)
{
$user = Auth::user();
if ($user->level > $level) {
return redirect('testUrl');
}
return $next($request);
}
This would help.
Edit: 14 Dec 2018
You can also send multiple variables to middleware. You just need to seperate the values using a comma (,).
Route::group(['middleware' => 'checkUserLevel:some_value_of_level, one_more_value_to_send'], function () {
// my routes
});
And you will get the value one_more_value_to_send in the variable after $level in the middleware handler.
public function handle($request, Closure $next, $level, $another_value)
{
$user = Auth::user();
if ($user->level > $level) {
return redirect('testUrl');
}
return $next($request);
}
For more details you can refer to: Passing parameters to Middleware in Laravel 5.1
In Laravel 6.x you have to do this
add code like in your middleware
public function handle($request, Closure $next,$module=null,$right=null)
{
dd($module,$right);
return $next($request);
}
your route code like this
Route::get('/department/add', 'DepartmentController#addNew')->middleware('ManualSec:abc,xyz');
In Kernel.php register your middleware in the section of $routeMiddleware like
'ManualSec' => \App\Http\Middleware\ManualSec::class,
by calling the rout using url in my case
http://local.pms.com:8080/department/add
it will result is like:
now you can code in your middleware
I am using Sentinel to authenticate users and as the auth Middleware.
Middleware code:
public function handle($request, Closure $next)
{
var_dump(Sentinel::guest()); // prints false
if (Sentinel::guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/login');
}
}
return $next($request);
}
Controller code:
public function getAccount() {
var_dump(Sentinel::guest()); // prints true
return Sentinel::getUser();
}
routes.php
Route::group(['middleware' => ['auth']], function () {
Route::get('api/v1/temp/users/account', 'App\Http\Controllers\UsersController#getAccount');
}
Then if i browse to api/v1/temp/users/account the var_dump() in the Middleware is printing false, while the var_dump() inside the controller is printing true which seems a nonsense.
What's wrong?
It turned out i was using the native facade instead of the Laravel facade Cartalyst\Sentinel\Laravel\Facades\Sentinel. That fixed.