I want to split middleware auth to two role one is for admin and second for user
but some route is use for all user and admin and few route is for admin only how can i split with route?
Auth::routes();
Route::group(['middleware' => 'auth'], function () {
//Some route here
});
Route::group(['middleware' => ['guest']], function () {
//some route here
});
Here is my implementation for access control for admin and users(agents in my case) I have a boolean field in my user table (is_admin) which is 0 for normal users and 1 for admins.
In your User model add this:
protected $casts = [
'is_admin' => 'boolean',
];
public function isAdmin()
{
return $this->is_admin;
}
Create a new middlewares for Admin and Agent:
php artisan make:middleware Admin
php artisan make:middleware Agent
The middleware files will be created in App\Http\Middleware\
Add this to class inside Admin.php:
public function handle($request, Closure $next)
{
if ( Auth::check() && Auth::user()->isAdmin() )
{
return $next($request);
}
return redirect('/agent');
}
Add this to Agent.php
public function handle($request, Closure $next)
{
if ( Auth::check() && !Auth::user()->isAdmin() )
{
return $next($request);
}
return redirect('/home');
}
After this register your middleware with laravel to do this add this to protected $routeMiddleware in your Kernel.php which is located at app\Http\Kernel.php
'admin' => 'App\Http\Middleware\Admin',
'agent' => 'App\Http\Middleware\Agent',
Make sure to create proper routes for redirection as we've mentioned in our middleware files. After this you are almost done. Now to verify if a user is admin or normal user add this to the constructor method of your controller.
Actions allowed only for admin users:
public function __construct()
{
$this->middleware('auth');
$this->middleware('admin');
}
Action allowed only for normal (agent) users:
public function __construct() {
$this->middleware('auth');
$this->middleware('agent');
}
Or you can also add middleware to your routes,
Route::group(['middleware' => 'admin'], function () {
//Some route here
});
Related
I have got a table with my permissions, I want to be able to setup a route like below so that I check the logged in users permissions and see if they have got access to the edit_users page for example.
Route::group([ 'prefix' => 'users', 'middleware' => 'can:access,edit_users' ], static function() {
I have added the following Gate, where I would do my query and check, however $permission is null...
public function boot()
{
$this->registerPolicies();
Gate::define('access', static function ($user, $permission) {
dd($user, $permission);
});
}
How would I go about doing this? As I don't want to hard-code all the permissions into gates!
The default middleware passes a route parameter as the second argument. I think what you'll need to do in this case is write your own middleware that takes a string as the argument, then do your check manually.
namespace App\Http\Middleware;
use Closure;
class HasPermission {
public function handle($request, Closure $next, $permission)
{
if($request->user()->can('access', $permission)) {
return $next($request);
}
return redirect()->back();
}
}
Then register your new middleware in the kernel file
'hasPermission' => \App\Http\Middleware\HasPermission::class
Then you can use your new middleware instead of the can middleware in your route.
Route::group([ 'prefix' => 'users', 'middleware' => 'hasPermission:edit_users' ], function() {});
I am using middleware in laravel. I have two middleware one is admin and second one is commissioner
Now in both middlewares some routes access to both middleware and some are not. Now what happen is i want personal routes of admin middleware not be accessed in commissioner middleware.
Here i have tried:-
//Admin Middleware Route
Route::group(["middleware" => ['admin']], function () {
Route::match(['get', 'post'], '/admin/users', 'AdminController#users');
});
//Commissioner Middleware Route
Route::group(["middleware" => ['commissioner']], function () {
//we can put later on these routes
});
// common middleware routes between commissioner and admin
Route::group(["middleware" => ['admin','commissioner']], function () {
Route::match(['get', 'post'], '/admin/dashboard', 'AdminController#dashboard');
Route::match(['get', 'post'], '/admin/profile', 'AdminController#profile');
});
Now when i access the AdminController#users route when i login through commissioner it is accessible but i want that route not be accessed in when commissioner login. but AdminController#dashboard and AdminController#profile should be accessible in both middleware
When admin login then type is : master
when commsioner login then type is : commissioner
// Commissioner Middleware
class Commissioner
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(empty(Session::has('adminSession'))){
return redirect()->action('AdminController#login')->with('flash_message_error', 'Please Login');
}
return $next($request);
}
}
// admin Middleware
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(empty(Session::has('adminSession'))){
return redirect()->action('AdminController#login')->with('flash_message_error', 'Please Login');
}
return $next($request);
}
}
Please help me i am using laravel 5.2. Thanks in advnace :)
If I understand your problem correctly, you have one admin table which contains tow different types of admins: master and commissioner.
These two types of admins are both logined in by invoke AdminController#login method. You want to use middleware to check the types of the admin to protect your routes.
Below is my suggestions:
Create three different middlewares:
AdminAuth middleware (give it a name in Http/Kernel.php as "admin") for authentication checking for both master and commissioner.
Master middleware (give it a name in Http/Kernel.php as "master") check master type admin.
Commissioner middleware (give it a name in Http/Kernel.php as "commissioner") check commissioner type admin.
Middlewares:
class AdminAuth
{
public function handle($request, Closure $next)
{
if(!Session::has('adminSession')){
return redirect()->action('AdminController#login')->with('flash_message_error', 'Please Login');
}
return $next($request);
}
}
class Master
{
public function handle($request, Closure $next)
{
$admin = ... // Your code to retrived authenticated admin instance.
if($admin->type !== 'master') { // I assume you have a type field.
// return error here to indicate user is not a master
}
return $next($request);
}
}
class Commissioner
{
public function handle($request, Closure $next)
{
$admin = ... // Your code to retrived authenticated admin instance.
if($admin->type !== 'commissioner') { // I assume you have a type field.
// return error here to indicate user is not a commissioner
}
return $next($request);
}
}
Update your route like below:
Routes:
//Admin Middleware Route can only be accessed by master admin
Route::group(["middleware" => ['admin', 'master']], function () {
Route::match(['get', 'post'], '/admin/users', 'AdminController#users');
});
//Commissioner Middleware Route
Route::group(["middleware" => ['admin', 'commissioner']], function () {
//we can put later on these routes
});
// common middleware routes between commissioner and admin
Route::group(["middleware" => ['admin']], function () {
Route::match(['get', 'post'], '/admin/dashboard', 'AdminController#dashboard');
Route::match(['get', 'post'], '/admin/profile', 'AdminController#profile');
});
BTW, the middlewares are "AND" relationship. Say you have below declaration in your routes:
"middleware" => ['admin', 'commissioner']
This means the route can be accessed only when you passed both 'admin' and 'commissioner' checking.
I have a roles administrator, moderator and member in my laravel application. Application have fronted and backend sections. I want to allow access to backend section only for administrator and moderator. I create SuperUsersMiddleware:
<?php
namespace CMS\Http\Middleware;
use Closure;
class SuperUsersMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (! $request->user()->hasRole('administrator') || ! $request->user()->hasRole('moderator')) {
return redirect('/');
}
return $next($request);
}
}
Register in Kernel.php:
......
protected $routeMiddleware = [
'superusers' => \CMS\Http\Middleware\SuperUsersMiddleware::class,
'administrator' => \CMS\Http\Middleware\AdminMiddleware::class,
'moderator' => \CMS\Http\Middleware\ModeratorMiddleware::class,
'auth' => \CMS\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \CMS\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
.....
and in my backend folder I create Controller.php (all other controllers in backend section extends this controller) and in __construct() function set middleware:
...
public function __construct()
{
$this->middleware('superusers');
}
...
But this doesn't work for me. I also create administrator and moderator middleware and it works separately but I needed both - together. How to do that? I tray:
public function __construct()
{
$this->middleware('administrator');
$this->middleware('moderator');
}
But this also can't work. What is a best practice for this situation?
First off I wouldn't apply any Middleware on your master Controller as then middleware would be applied to everything. You should do this on each individual controller like UserController.
You can apply as many middleware instances to a route/function as you want. I'm not aware of any limitations on that. So I'm not sure why you say this doesn't work:
public function __construct()
{
$this->middleware('administrator');
$this->middleware('moderator');
}
You can apply the different middleware to the routes that require the different levels. You can do this in your routes.php or in your Controllers. If you want to do it in your Controller like you are doing above you would have something like this:
public function __construct()
{
$this->middleware('auth'); //this applies to all actions
$this->middleware('administrator', ['only' => ['adminFunction', 'otherAdminFunction','bothCanAccess']]);
$this->middleware('moderator',['only' => ['moderatorFunction','bothCanAccess']);
}
public function adminfunction()
{
...
}
public function otherAdminfunction()
{
...
}
public function moderatorFunction()
{
...
}
public function bothCanAccess()
{
...
}
So first off the auth middleware will apply to all actions. This means a user has to be logged in to access any function in here. Then you can apply specific middleware to each function. If you need more info on this check out the documentation:
https://laravel.com/docs/5.2/controllers#controller-middleware
To do this in your router you would do something like this:
Route::get('/admin', ['middleware' => ['auth', 'administrator'],'uses'=>'Controller#adminFunction']);
So in this case it will apply the auth middleware first to make sure someone is logged in, then fire the administrator middleware and make sure the user is an admin.
Hopefully that helps.
I am creating a project where i have multiple user types, eg. superadmin, admin, managers etc. Once the user is authenticated, the system checks the user type and sends him to the respective controller. The middle ware for this is working fine.
So when manager goes to http://example.com/dashboard he will see the managers dashboard while when admin goes to the same link he can see the admin dashboard.
The below route groups work fine individually but when placed together only the last one works.
/***** Routes.php ****/
// SuperAdmin Routes
Route::group(['middleware' => 'App\Http\Middleware\SuperAdminMiddleware'], function () {
Route::get('dashboard', 'SuperAdmin\dashboard#index'); // SuperAdmin Dashboard
Route::get('users', 'SuperAdmin\manageUsers#index'); // SuperAdmin Users
});
// Admin Routes
Route::group(['middleware' => 'App\Http\Middleware\AdminMiddleware'], function () {
Route::get('dashboard', 'Admin\dashboard#index'); // Admin Dashboard
Route::get('users', 'Admin\manageUsers#index'); // Admin Users
});
I know we can rename the routes like superadmin/dashboard and admin/dashboard but i was wondering if there is any other way to achieve the clean route. Does anyone know of any anywork arounds ?
BTW i am using LARAVEL 5.1
Any help is appreciated :)
You can do this with a Before Middleware that overrides the route action's namespace, uses and controller attributes:
use Closure;
use Illuminate\Http\Request;
use Illuminate\Contracts\Container\Container;
use App\Http\Middleware\AdminMiddleware;
use App\Http\Middleware\SuperAdminMiddleware;
class AdminRoutingMiddleware
{
/**
* #var Container
*/
private $container;
public function __construct(Container $container)
{
$this->container = $container;
}
private static $ROLES = [
'admin' => [
'namespace' => 'Admin',
'middleware' => AdminMiddleware::class,
],
'super' => [
'namespace' => 'SuperAdmin',
'middleware' => SuperAdminMiddleware::class,
]
];
public function handle(Request $request, Closure $next)
{
$action = $request->route()->getAction();
$role = static::$ROLES[$request->user()->role];
$namespace = $action['namespace'] . '\\' . $role['namespace'];
$action['uses'] = str_replace($action['namespace'], $namespace, $action['uses']);
$action['controller'] = str_replace($action['namespace'], $namespace, $action['controller']);
$action['namespace'] = $namespace;
$request->route()->setAction($action);
return $this->container->make($role['middleware'])->handle($request, $next);
}
}
This way you have to register each route only once without the final namespace prefix:
Route::group(['middleware' => 'App\Http\Middleware\AdminRoutingMiddleware'], function () {
Route::get('dashboard', 'dashboard#index');
Route::get('users', 'manageUsers#index');
});
The middleware will convert 'dashboard#index' to 'Admin\dashboard#index' or 'SuperAdmin\dashboard#index' depending on current user's role attribute as well as apply the role specific middleware.
The best solution I can think is to create one controller that manages all the pages for the users.
example in routes.php file:
Route::get('dashboard', 'PagesController#dashboard');
Route::get('users', 'PagesController#manageUsers');
your PagesController.php file:
protected $user;
public function __construct()
{
$this->user = Auth::user();
}
public function dashboard(){
//you have to define 'isSuperAdmin' and 'isAdmin' functions inside your user model or somewhere else
if($this->user->isSuperAdmin()){
$controller = app()->make('SuperAdminController');
return $controller->callAction('dashboard');
}
if($this->user->isAdmin()){
$controller = app()->make('AdminController');
return $controller->callAction('dashboard');
}
}
public function manageUsers(){
if($this->user->isSuperAdmin()){
$controller = app()->make('SuperAdminController');
return $controller->callAction('manageUsers');
}
if($this->user->isAdmin()){
$controller = app()->make('AdminController');
return $controller->callAction('manageUsers');
}
}
I follow this tutorial : https://www.youtube.com/watch?v=kmJYVhG6UzM Currently I can check in my blade if user is a admin or not like this:
{{ Auth::user()->roles->toArray()[0]['role'] }}
HI ADMIN
#endif
How can I make my route only available for admin user?
You need to create a middleware for your route.
Use: php artisan make:middleware AdminMiddleware.
You will find in your middleware folder a new file with this name.
Put your logic in your middleware, e.g.
public function handle($request, Closure $next)
{
if(Auth::check())
{
return $next($request);
}
else
{
return view('auth.login')->withErrors('You are not logged in');
}
}
Once you have done your logic in your middleware, you can either call it in the route or make the middleware apply to all routes.
If you want to add it to all routes, go to Kernel.php and add it to the $middleware array, e.g.
protected $middleware = [
'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
'Illuminate\Cookie\Middleware\EncryptCookies',
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
'App\Http\Middleware\VerifyCsrfToken',
'App\Http\Middleware\AdminMiddleware',
];
If you want to add it to specific routes only, add it to the $routeMiddleware variable and add the alias to the route. E.g.
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
'admin' => 'App\Http\Middleware\AdminMiddleware',
];
You can then add it to a route, as a filter, e.g.
Route::get('admin/profile', ['middleware' => 'admin', function()
{
}]);
For additional info visit the docs:
http://laravel.com/docs/master/middleware
EDIT
An improvement on this would be to use variadic functions which was introduced in PHP 5.6
http://php.net/manual/en/migration56.new-features.php
Instead of having to make a middleware for each permission set you can do the following
PermissionMiddleware
namespace App\Http\Middleware;
use Closure;
use \App\Models\Role;
class PermissionMiddleware
{
// Pass parameters to this middleware
public function handle($request, Closure $next, ...$permitted_roles)
{
//Get a users role
$role = new Role;
$role_name = $role->getUserRoleByName();
foreach($permitted_roles as $permitted_role) {
if($permitted_role == $role_name) {
return $next($request);
}
}
return redirect()->back()->withErrors('You do not have the required permission');
}
}
Notice the ...$permitted_roles
Route::get('admin/profile', ['middleware' => 'PermissionMiddleware:Admin,Marketing', function()
{
}]);
You can now specify as many roles as required for one middleware rather than creating multiple by using middleware parameters
Docs
https://laravel.com/docs/5.3/middleware#middleware-parameters
Let's assume you have a column in your users table with isAdmin name which has a default value of 0 (false)
You can give special access using middleware in laravel like you give access to logged in users using auth middleware in laravel.
Now you need to create a middleware using the command :
php artisan make:middleware AdminMiddleware
In your Kernel.php you need to add this line to protected $routeMiddleware
'admin' => \App\Http\Middleware\AdminMiddleware::class,
In your middleware folder you have the AdminMiddleware file.
In that you need to put your logic
In this case this is how it might look like depending upon you
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RoleMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(Auth::user()->isAdmin == '1') // is an admin
{
return $next($request); // pass the admin
}
return redirect('/'); // not admin. redirect whereever you like
}
}
Now in your route you have to pass the url using this middleware
Here is how it might look like
Route::get('/iamanadmin', ['middleware' => 'admin', function() {
return view('iamanadmin');
}]);
use middleware and check for admin user.
Route::get('admin', ['middleware' => 'checkadmin', function()
{
}]);
now create middleware and validate admin user.