laravel one route with multiple controllers based on user role - php

So i'm trying to achieve something, that seems is impossible. I want some routes in my application to use different controller based on user role. This is the approach i'm trying, but it doesn't work well. The user routes work, but admin routes return and Trying to get property on non object error in the VerifyCsrfToken.php file*
Route::group(array('middleware' => 'isAdmin'), function() {
Route::get('/', 'Admin\TestController#getIndex');
});
Route::group(array('middleware' => 'isUser'), function() {
Route::get('/', 'User\TestController#getIndex');
});
My middlewares
public function handle($request, Closure $next)
{
if(Auth::user()->isAdmin()) {
return $next($request);
}
}
public function handle($request, Closure $next)
{
if(Auth::user()->isUser()) {
return $next($request);
}
}
I've seen some handle this kind of situation, by just handling this in the controllers or even checking the use role inside the routes file, but I would rather use middlwares, so my routes file would be cleaner

You can do something like this:
Route::get('/', function () {
if (auth()->check()) {
if (auth()->user()->isAdmin()) {
return redirect()->route('');
} elseif (auth()->user()->isUser()) {
return redirect()->route();
} else {
return view('index');
}
}
return redirect()->to('login');
});

The error message has probably nothing to do with the code your show.
But using multiple controllers on one route is impossible, I asked the same question once.
But you could just use one controller and handle the authorization in that controller.
For example:
public function getIndex()
{
if(Auth::user()->isAdmin()) {
//Admin
return $this->getAdminIndex();
} else {
//No admin
return $this->getUserIndex();
}
}
protected function getAdminIndex()
{
return view('admin.index');
}
protected function getUserIndex()
{
return view('user.index');
}
But the cleanest way to do it is to just have 2 routes.

Related

Laravel routing with conditions

How does it(route:caching) work under hood and will it breake logic if I cached my routes.
I have a webhook which send me data to one single route. The data are difference only by objects fields. Will it correct to split it to different routes or I am need to make index method which will be redirect my logic by methods
Route::group(['namespace' => 'Webhook'], function () {
if (Request::has('message')) {
Route::post('/', 'WebhookController#message');
}
if (Request::has('callback_query')) {
Route::post('/', 'WebhookController#callback');
}
});
You can shorten the routes code to this:
Route::group(['namespace' => 'Webhook'], function () {
Route::post('/', 'WebhookController#handle');
});
And do the "heavy work" in the controller:
class WebhookController extends Controller
{
public function handle(Request $request)
{
if ($request->has('message')) {
return $this->message();
}
if ($request->has('callback_query')) {
return $this->callback();
}
}
public function message();
public function callback();
}
This is equivalent to:
Route::group(['namespace' => 'Webhook'], function () {
Route::post('/', function(Request $request) {
if ($request->has('message')) {
return (new WebhookController)->message();
}
if ($request->has('callback_query')) {
return (new WebhookController)->callback();
}
});
});
You can use middleware for such kind of logics.
Laravel Middleware

Add Multiple Middleware to Laravel Project

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.

How to check user Permissions using Custom Middleware in Laravel

I'm developing a Laravel ACL System. My base Table's are users,roles,permissions and pivot tables are role_user,role_permission,user_permission.
I want to check User Permissions using my custom middleware HasPermission. I have tried this way but it's not working properly. every user can access the all the permissions which have or have not.
Now, How can I solve the issue. Please see my code sample.
My Controller.
function __construct()
{
$this->middleware('auth');
$this->middleware('HasPermission:Role_Read|Role_Update|Role_Delete');
}
My Middleware.
class HasPermission
{
public function handle($request, Closure $next,$permissions)
{
$permissions_array = explode('|', $permissions);
// $user = $this->auth->user();
foreach($permissions_array as $permission){
if(!$request->user()->hasPermission($permission)){
return $next($request);
}
}
return redirect()->back();
}
}
and, my User Model method.
public function user_permissions()
{
return $this->belongsToMany(Permission::class,'user_permission');
}
public function hasPermission(string $permission)
{
if($this->user_permissions()->where('name', $permission)->first())
{
return true;
}
else
{
return false;
}
}
Best way to do is that you need to introduce an new service provider and in that you can check the authorization and permissions.
I made a test project (last year) for db driven permission and I used service provider.
That's the perfect way to implement.
Basically !$request->user()->hasPermission($permission) is saying if the user associated with the request does not have this permission the middleware passes, however this is not what you want. Here's what you should do:
If you need the user to have one of the stated permissions you need to do:
class HasPermission
{
public function handle($request, Closure $next,$permissions)
{
$permissions_array = explode('|', $permissions);
foreach($permissions_array as $permission){
if ($request->user()->hasPermission($permission)){
return $next($request);
}
}
return redirect()->back();
}
}
If you want the user to have all stated permissions you need to do:
class HasPermission
{
public function handle($request, Closure $next,$permissions)
{
$permissions_array = explode('|', $permissions);
foreach($permissions_array as $permission){
if (!$request->user()->hasPermission($permission)){
return redirect()->back();
}
}
return $next($request);
}
}
As an added note if you want to do this in a more elegant way you can do:
class HasPermission
{
public function handle($request, Closure $next, ...$permissions_array)
{
//Function body from above without the explode part
}
}
And
function __construct()
{
$this->middleware('auth');
$this->middleware('HasPermission:Role_Read,Role_Update,Role_Delete');
}
If you use commas then the framework will split the string into arguments for you .
In my case i just added simple function to get permissions from database and then check it Middleware. Check this code:
// Add new function to get permissions from database
public static function user_permissions($user) {
$permissions=DB::table('permissions')->where('user_id', $user)->first();
return $permissions;
}
// In Middleware check your permissions
if(Auth::guest())
{
return redirect('/');
}
elseif(Functions::user_permissions(Auth::user()->id)->user_managment != 1) {
return redirect('/');
} else {
return $next($request);
}
In web.php/api.php:
Route::middleware('hasPermission')->group(function() { // for all routes
Route::get('/article', [ArticleController::class, 'index'])->name('article.index');
});
in middleWare:
class HasPermission
{
public function handle($request, Closure $next)
{
$routeName = Request::route()->getName();
$permission = $user->permissions()->where('route_name', $routeName)->first();
if ( ! empty($permission)){
return redirect()->back();
}
return $next($request);
}
}

Laravel 5.1 Sentinel::getUser() return null

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.

Laravel 5.1 page authentication using routes

I'm working on a site that needs an admin panel. I am currently trying to set up the authentication of that panel, though I can not find a way to deny access from any guest users (non-admins). I have a login page, of course, and after login, it routes to the admin page, though you can also go to /admin when you're not logged in.
routes.php :
Route::get('home', function(){
if (Auth::guest()) {
return Redirect::to('/');
} else {
return Redirect::to('admin');
}
});
Route::get('admin', function () {
return view('pages.admin.start');
});
MainController.php :
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class MainController extends Controller {
public function getIndex() {
return view('pages.index');
}
public function getAbout() {
return view('pages.about');
}
public function getPortfolio() {
return view('pages.portfolio');
}
public function getShop() {
return view('pages.shop');
}
public function getContact() {
return view('pages.contact');
}
/*public function getAdmin() {
return view('pages.admin.start');
}*/
}
I could really use some help here, because I'm totaly stuck, and yes, I have read the documentation, though maybe I'm just missing something.
Assuming you have a line like this:
'auth' => 'App\Http\Middleware\Authenticate',
in your app/Http/Kernel.php file:
put all the routes you need "authenticated" inside the grouping, but keep the "guest" routes outside of them :
Route::get('home', function(){
if (Auth::guest()) {
return Redirect::to('/');
} else {
return Redirect::to('admin');
}
});
Route::group( ['middleware' => 'auth' ], function(){
Route::get('admin', function () {
return view('pages.admin.start');
});
Route::just-another-route()...;
Route::just-another-route()...;
});
Documentation: http://laravel.com/docs/5.1/routing#route-groups
You should use a Middleware to handle authentication of your users
1) First you have to create a middleware that will check if the user requiring the page is an admin, and if not you have to redirect; something like this:
class AdminMiddleware
{
public function handle(Request $request, Closure $next )
{
//if User is not admin
//redirect to no permess
return $next($request);
}
}
2) Then you have to bind the middleware to the routes you want to be accessible only from an admin user:
//bind the middleware to all the routes inside this group
Route::group( ['middleware' => 'adminmiddleware' ], function()
{
Route::get('admin', function () {
return view('pages.admin.start');
});
//other routes
});

Categories