I changed the users table and put a field called "role" and was wondering if it is possible to use middleware to protect routes only by checking this field.
The table users:
I wnated something like this:
If user role == 0
Route::group(['middleware' => 'auth'], function () {});
If user role == 1
Route::group(['middleware' => 'auth:customers'], function () {});
However with the same table
Make a new middleware:
php artisan make:middleware CustomerMiddleware
The function handle in the new middleware:
public function handle($request, Closure $next)
{
if(Auth::check()){
if($request->user()->role != 0){
return redirect('/');
}
}
return $next($request);
}
The protected route in app/Http/Kernel.php
'CustomerMiddleware' => \App\Http\Middleware\CustomerMiddleware::class,
The group routes:
Route::group(['middleware' => 'CustomerMiddleware'], function () { });
Related
I'm using spatie/laravel-permission to add permissions for my routes.
One of the routes I have can be accessed by two permissions (earnings, financial_fund). The user doesn't need to have both permissions to access the controller. He can access the controller by having one of the permissions or both of them.
I've tried to write something like this.
Route::group(['middleware' => ['can:earnings']], function () {
Route::get('/payment', [PaymentsController::class, 'getAll']);
Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
});
Route::group(['middleware' => ['can:financial_fund']], function () {
Route::get('/payment', [PaymentsController::class, 'getAll']);
Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
});
But the above code allows only users with can:earnings permission to access the routes, it doesn't allow users with can:financial_fund permission.
I've also tried to write something like this
Route::group(['middleware' => ['can:earnings,financial_fund']], function () {
Route::get('/payment', [PaymentsController::class, 'getAll']);
Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
});
But this requires both of permissions to exist with the current user.
How can I tell that I want only one of the permissions at least to exist?
I have found that Laravel has introduced the canAny for use in blade templates. Is there a way I can use it in my api.php file while defining the Routes?
I fixed it by creating a new middleware
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class AuthorizeCanAny
{
public function handle(Request $request, Closure $next, ...$permissions)
{
if (!$request->user()) {
abort(403);
}
$userPermissions = array_map(function ($e) {
return $e['name'];
}, $request->user()->permissions->toArray());
$userPermissionsIntersect = array_intersect($userPermissions, $permissions);
if (!sizeof($userPermissionsIntersect)) {
abort(403);
}
return $next($request);
}
}
Adding the middleware to kernal.php file
protected $routeMiddleware = [
...,
'canAny' => AuthorizeCanAny::class,
];
Then use it in the router
Route::group(['middleware' => ['canAny:earnings,financial_fund']], function () {
Route::get('/payment', [PaymentsController::class, 'getAll']);
Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
});
how to create middleware redirect about role. I have 2 middleware, first Admin, next User. Need redirect after login, if role Admin, example redirect to /admin, if User redirect to /user.
Admin middleware:
if(Auth::check() && Auth::user()->isRole() == "Admin"){
return $next($request);
}
return redirect('login');
User middleware:
if(Auth::check() && Auth::user()->isRole() == "User"){
return $next($request);
}
return redirect('login');
WEB routes
Route::group(['middleware' => ['auth']], function () {
Route::get('/', 'DashboardController#index');
Route::group(['middleware' => ['auth' => 'admin']], function (){
Route::resource('/admin', 'AdminController');
});
Route::group(['middleware' => ['auth' => 'user']], function (){
Route::resource('/user', 'AdminController');
});
});
You can make your admin/user middleware to inherit laravel's Authenticate middleware: Illuminate\Auth\Middleware\Authenticate, then have their definitions as below.
Admin Middleware-
public function handle($request, Closure $next, ...$guards)
// Ensure auth - this will automagically re-direct if not authed.
$this->authenticate($request, $guards);
if(Auth::user()->isRole() == "Admin")
return $next($request);
return redirect('/user-default-page')
}
// You can define this for your un-authenticated redirects
protected function redirectTo($request)
{
return '/login';
}
User middleware will then be:-
public function handle($request, Closure $next, ...$guards)
// Ensure auth - this will automagically re-direct if not authed.
$this->authenticate($request, $guards);
if(Auth::user()->isRole() == "User")
return $next($request);
return redirect('/admin-default-page')
}
// You can define this for your un-authenticated redirects
protected function redirectTo($request)
{
return '/login';
}
For routes:
Route::group(['middleware' => 'admin'], function () {
// Put here admin routes, e.g
Route::resource('/admin', 'AdminController');
}
Route::group(['middleware' => 'user'], function () {
// Put here user routes, e.g
Route::resource('/users', 'UserController');
}
// You can still use the default auth routes, say for routes that (somehow), both admin and user can access
Route::group(['middleware' => 'auth'], function () {
Route::resource('/dashboard', 'DashboardController');
}
// Admin Middleware
public function handle($request, Closure $next)
{
if(Auth::check() && Auth::user()->role->id == 1)
{
return $next($request);
}else {
return redirect()->route('login');
}
}
// User Middleware
public function handle($request, Closure $next)
{
if(Auth::check() && Auth::user()->role->id == 2 )
{
return $next($request);
}else {
return redirect()->route('login');
}
}
// Admin Route Group
Route::group(['as'=>'admin.','prefix'=>'admin','namespace'=>'Admin','middleware'=>['auth','admin']], function (){
Route::get('dashboard','DashboardController#index')->name('dashboard');
})
// User Middleware
Route::group(['as'=>'user.','prefix'=>'user','namespace'=>'Author','middleware'=>['auth','user']], function (){
Route::get('dashboard','DashboardController#index')->name('dashboard');
});
I have problem to make routing with middleware multi roles
I have tried some in internet but still wont work
I have 3 roles, superadmin, admin and member
I want the superadmin and admin can access the add page
here is my code :
Route::group(['prefix' => 'staff', 'middleware' => 'auth'], function () {
Route::GET('/add', [
'uses' => 'StaffController#page_add',
'middleware' => 'rule:superadmin', ???
]);
});
I have tried to put 'middleware' => 'rule:superadmin|rule:admin'
but wont work
thank you
Create a middleware file eg Role.php
public function handle($request, Closure $next, ... $roles)
{
if (!Auth::check()) // I included this check because you have it, but it really should be part of your 'auth' middleware, most likely added as part of a route group.
return redirect('login');
$user = Auth::user();
if($user->isAdmin())
return $next($request);
foreach($roles as $role) {
// Check if user has the role This check will depend on how your roles are set up
if($user->hasRole($role))
return $next($request);
}
return redirect('login');
}
Finally in your web routes
Route::get('admin/scholen/overzicht', 'SchoolsController#overview')->middleware('role:editor,approver');
Route::get('admin/scholen/{id}/bewerken', 'SchoolsController#edit')->middleware('role:admin');
Check out this best answer for more details
Hey you can put a column named "role" in your users table then check it with a condition.
Route::get('/add', function() {
if (Auth::user()->role == 'superadmin' || Auth::user()->role == 'admin') {
return view('add-page');
}
else {
return view('error-page');
}
});
I have 3 roles roles, admin, tutor and student. i want to place them in 3 different goups, i however want the admin to be in all the groups. I have tried different methods to add the admin to other routes but it's not working. How can i make admin use all routes in tutor's middleware? Here is my code
AdminMiddleware, similar to all the others
class AdminMiddleware
{
public function handle($request, Closure $next)
{
if(Auth::check() && Auth::user()->isRole()=="admin") {
return $next($request);
}
return redirect('login');
}
}
routesmiddleware - in web.php
Route::group(['middleware'=>['auth'=>'admin']], function (){
//admin routes
}
Route::group(['middleware'=>['auth'=>'tutor']], function (){
//tutor routes
}
in the Kernel.php
'admin' => \App\Http\Middleware\AdminMiddleware::class,
'tutor' => \App\Http\Middleware\TutorMiddleware::class,
'student' => \App\Http\Middleware\StudentMiddleware::class,
in user model
public function isRole(){
return $this->role;
}
What you can do is define a middleware that takes the supported roles as argument:
class HasRoleMiddleware
{
public function handle($request, Closure $next, ...$roles)
{
if(Auth::check() && in_array(Auth::user()->getRole(), $roles)) {
return $next($request);
}
return redirect('login');
}
}
This middleware expects that User::getRole() returns the role as string, i.e. admin or tutor. Then you need to define the middleware in Kernel.php as you have already done:
'any_role' => \App\Http\Middleware\HasRoleMiddleware::class,
And finally you can use the middleware like this:
Route::group(['middleware' => 'auth'], function () {
Route::group(['middleware' => 'any_role:admin'], function () {
// admin routes
}
Route::group(['middleware' => 'any_role:admin,tutor'], function () {
// tutor routes
}
}
As you can see, I've also nested the route groups which perform role checks inside another route group which checks for authentication. This makes it more readable and reduces the risk you forget an authentication check in a future extension of your routes.
I am using middleware for route groups and have three middlewares admin, teacher, and teacheradmin
Well admin is working fine but suppose I have 10 routes and all of them defined under group teacheradmin (working case for now)
but I want only 5 of those 10 routes to be accessed by middleware teacher and all 10 to be accessed by middleware teacheradmin
this is how I nested route groups
Route::group(['middleware' => 'teacheradmin'], function() {
//defined 5 routes only accessible by teacheradmin
Route::group(['middleware' => 'teacher'], function() {
//defined the other routes accessible by both teacher and teacheradmin
});
});
but the above nesting is not working, teacheradmin is not able to access the routes defined under teacher
plz I need a direction on how can I make it work
Update:
as per the answer I have defined middleware array for common routes
Route::group(['middleware' => ['teacher', 'teacheradmin']], function() {
//defined common routes
});
and the handle methods for teh two middleware is:
teacher
public function handle($request, Closure $next)
{
if(Auth::check())
{
if(Auth::user()->user_type != 'TEACHER')
{
return redirect()->route('dashboard');
}
return $next($request);
}
else
{
return redirect('/')
->withErrors('That username/password does not match, please try again !!!.');
}
}
teacheradmin
public function handle($request, Closure $next)
{
if(Auth::check())
{
if(Auth::user()->user_type != 'TEACHER_ADMIN')
{
return redirect()->route('dashboard');
}
return $next($request);
}
else
{
return redirect('/')
->withErrors('That username/password does not match, please try again !!!.');
}
}
and the dashboard route goes to this method
public function Dashboard(Request $request)
{
$user = Auth::user();
if($user->user_type === 'ADMIN') {
return redirect()->route('dashboardadmin');
} else if($user->user_type === 'TEACHER_ADMIN') {
return redirect()->route('dashboardteacher');
} else if($user->user_type === 'TEACHER') {
return redirect()->route('world_selection');
} else {
return redirect()->route('dashboardchild');
}
}
now the problem I am facing is when I am on dashboard and I try to access a common route as teacheradmin then it also goes to handle of teacher hence coming back to the same page again
Not sure why you are nesting them. You can attach multiple middleware via array notation to a group like this:
Route::group(['middleware' => 'teacheradmin'], function() {
//defined 5 routes only accessible by teacheradmin
});
Route::group(['middleware' => ['teacher', 'teacheradmin']], function() {
//defined the other routes accessible by both teacher and teacheradmin
});
Update:
I think what you are trying to do can be done by using just one middleware with middleware parameters:
Route::group(['middleware' => 'role:teacheradmin'], function() {
//defined 5 routes only accessible by teacheradmin
});
Route::group(['middleware' => 'role:teacher,teacheradmin'], function() {
//defined the other routes accessible by both teacher and teacheradmin
});
And in the role middleware:
public function handle($request, Closure $next, ...$roles)
{
dd($roles);
//Do your role checking here
return $next($request);
}
Disclaimer: ...$roles works from php 5.6 upwards.
As of Laravel 8 I would write it like:
Route::group(
['prefix' => 'v1', 'namespace' => 'Api'],
function(Router $router){
Route::get('/', function(){
return "Did you forget where you placed your keys??";
});
Route::post('/login', [LoginController::class, 'login']); //public
Route::get('/register', [LoginController::class, 'register']); //public
Route::group( //protected routes group
['middleware' => ['auth:sanctum']], //protected via some middleware
function () {
Route::get('/users', [UsersController::class, 'users']);
}
);
}
);