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() {});
Related
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
});
I am having trouble with Laravel routes. I'm trying to redirect to a controller after some middleware in the routes. But there is always this error.
The error is:
InvalidArgumentException in UrlGenerator.php line 558: Action
App\Http\Controllers\DashboardController#index not defined.
The route code is:
Route::get('/dashboard', ['middleware' => 'auth', function() {
return Redirect::action('DashboardController#index', array('user' => \Auth::user()));
}]);
The controller:
class DashboardController extends Controller
{
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
return view('dashboard')->with('user', \Auth::user());
}
}
But the above code actually works (so I guess that the controller actually works):
Route::get('/testdashboard', [
'uses' => 'DashboardController#index'
]);
So what is the problem? What is a valid route action?
This is might a better way to do it, change from
Route::get('/dashboard', ['middleware' => 'auth', function() {
return Redirect::action('DashboardController#index',
array('user' => \Auth::user()));
}]);
to
Route::get('/', [
'middleware' => 'auth',
'uses' => 'DashboardController#index'
]);
This is rather a comment than a post, but I can't send it at this time. I don't undestand why do you pass parameter (\Auth:user()) to a method that doesn't require it (but it's correct when you do it for the View).
Anyways I suggest you to work on your Middleware
public function handle($request, Closure $next)
{
if (Auth::check()) {
return redirect(...);
} else {
return redirect(...);
}
}
Use this route in place of your route and upgrade your Laravel Project to Laravel 8:
Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::get('/dashboard', 'DashboardController#index')->name('daskboard');
});
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 have two Middlewares: beforeCache & afterCache, boths registered on Kernel.
I want to call them into routes in this order:
1. beforeCache
2. myController
3. afterCache
If I define a route like this:
Route::get('especies/{id}', [
'middleware' => 'beforeCache',
'uses' => 'MyController#myMethod',
'middleware' => 'afterCache',
]);
beforeCache don't executes because afterCache is redefining the same array key middleware.
How should I do that? Thanks!
I'll assume you're using 5.1 in this, but what you're doing is essentially trying to define an array of attributes on the route. The brackets [] are just a shorthand version of saying array(...).
From the documentation (http://laravel.com/docs/5.1/middleware#defining-middleware) specifically the Before / After Middleware you simply just need to return a certain way.
For Before middlewares you do your code and return the next request after your code executes.
public function handle($request, Closure $next)
{
// Perform action
return $next($request);
}
For After middleware you handle the rest of the request and then your code executes and finally return the response.
public function handle($request, Closure $next)
{
$response = $next($request);
// Perform action
return $response;
}
The route would end up looking like this,
Route::get('especies/{id}',[
'middleware' => [
'beforeCache',
'afterCache'
],
'uses' => 'MyController#myMethod'
]);
class BeforeMiddleware implements Middleware {
public function handle($request, Closure $next)
{
// Do Stuff
return $next($request);
}
}
class AfterMiddleware implements Middleware {
public function handle($request, Closure $next)
{
$response = $next($request);
// Do stuff
return $response;
}
}
1-The before middleware operates and then passes on the request.
2-The after middleware allows the request to be processed, and then operates on it
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.