Laravel different routes for different roles - laravel

I have a Laravel app with different roles admin, buyer and seller. In the routes file, I have routes with a prefix of admin and users and when the prefix is user, I then also check the role. A buyers has different permissions than a seller.
Route::group(['prefix' => 'user'], function () {
Route::group(['middleware' => ['auth', 'roles', 'user'], 'roles' => ['buyer']], function() {
//
});
Route::group(['middleware' => ['auth', 'roles', 'user', 'owner:bids'], 'roles' => ['seller']], function() {
//
});
});
This is giving me some strange side effects. For instance I cannot have two same routes for buyer (user 1) and seller (user 2). I would want to have
http://localhost:8000/user/1/dashboard
but instead I need to do
http://localhost:8000/user/1/dashboard/buyer
http://localhost:8000/user/2/dashboard/seller
So I'm beginning to think I just need to discriminate between admin and users (and not by buyers and sellers as I'm doing above), and check the roles in the controller files, not in the route.
What is the better way of working with admin and user for which users can have multiple roles?

How is it that buyer and seller go to the same route and have the same id?
http://localhost:8000/user/1/dashboard
It is just one user that can do different actions then.
I would just add a field to users gate like is_admin and use some gates to check it. Same for your other similar question
https://laravel.com/docs/5.1/authorization#via-the-gate-facade

Related

How to set role name in prefix dynamically for same route group in laravel

I want to create dynamic prefix name according to logged user role name like for a same route group
if admin is login in admin panel then
url like :
http://localhost:8000/admin/dashboard
And, if dealer is login in admin panel :
http://localhost:8000/dealer/dashboard
my route group is
Route::group(['prefix' => 'admin', 'as' => 'admin.', 'namespace' => 'Admin', 'middleware' => ['auth', 'verified', 'preventBackHistory']], function () {
Route::get('/dashboard', 'HomeController#index')->name('home');
});
Basically My route group is same for admin & dealer
when i want different prefix according to user role when user is successfully login
It is a normal php file, so you may just add
if(...){ // if admin
$prefix = 'admin';
}else{ // if dealer
$prefix = 'dealer';
}
before your routes, and in your routes:
Route::group(['prefix' => $prefix, 'as' => $prefix.'.', 'namespace' => ucwords($prefix), 'middleware' => ['auth', 'verified', 'preventBackHistory']], function () {
Route::get('/dashboard', 'HomeController#index')->name('home');
});
Note: This is making a few assumptions about what you are doing.
You are not going to have access to the information about the current user until after the routes have been registered. The session has not started until after the request has been dispatched to a route and passes through the Middleware stack which will start the session. This is an idea of how to achieve that in a way that makes sense for the order of events.
You should setup the route group with a dynamic prefix:
Route::group(['prefix' => '{roleBased}', 'as' => 'admin.', 'namespace' => 'Admin', 'middleware' => ['auth', 'verified', 'dealWithPrefix', 'preventBackHistory']], function () {
Route::get('/dashboard', 'HomeController#index')->name('home');
});
Then in the RouteServiceProvider you will be adding a constraint for the prefix, parameter roleBased, to only allow it to be admin or client:
public function boot()
{
// restrict the prefix to only be 'admin' or 'dealer'
\Route::pattern('roleBased', 'admin|dealer');
parent::boot();
}
Now you will have to create a middleware to deal with getting the information of the current user to set a default for this prefix so that any URLs you generate to these routes will have this prefix and you don't have to pass a parameter for it. We will also remove the prefix parameter from the route so it does not get passed to your actions:
public function handle($request, $next)
{
$role = $request->user()->role; // hopefully 'admin' | 'client'
// setting the default for this parameter for the current user's role
\URL::defaults([
'roleBased' => $role
]);
// to stop the router from passing this parameter to the actions
$request->route()->forgetParameter('roleBased');
return $next($request);
}
Register this middleware in your kernel as dealWithPrefix. Note in the route group above this middleware was added to the list of middleware.
If you need to generate URLs to any routes in that group, and the current request isn't one of the routes in that group, you will be required to pass a parameter for this prefix when generating the URL:
route('admin.home', ['roleBased' => ...]);
If the request is currently for one of the routes in that group you will not need to add this parameter:
route('admin.home');
Note: This middleware could be applied in a wider way but you would need to know what default you want to use for this parameter if someone wasn't logged in. This is also assuming you may have more than just 1 route in that route group. If it is only that one single route then this can probably be adjusted slightly.

Laravel multi auth protecting route multple middleware not working

I have created an extra middleware admin and I want to protect my routes. Adding one single middleware 'auth' or 'auth:admin' is working.
Route::get('/calendar', function () {
return view('app', ['data' => []);
})->middleware('auth');
But I want that as an admin you can also access the user routes but this is not working. If I try the following, and I log in as an admin I get redirected to the login page all the time.
Route::get('/information', ['middleware' => ['auth', 'auth:admin'], function () {
return view('app', ['data' => ['auth' => Auth::check()]]);
}]);
But if I change ['auth', 'auth:admin'] to ['auth:admin','auth'] it is working for admin but not for user. So it seems that only the first element of my middleware in array is being recognized. Does anybody have any idea why my multiple middlewares are working seperate but not together? Any help is appreciated
If you are trying to allow multiple 'guards' to be checked for a route you can pass multiple guards as parameters to the Authenticate middleware, auth.
auth:web,admin (assuming web is your default guard).
This will try to resolve a user (Authenticatable) from each guard passed in. If any guard returns a user (Authenticatable) you pass through authenticated. If not you are a guest.
If you set the middleware auth and auth:admin those are 2 separate 'middleware' in the stack that are unrelated.
Route::get('/information', ['middleware' => ['auth', 'auth:admin'],function () {
return view('app', ['data' => ['auth' => Auth::check()]]);
}]);
in this code. ['auth', 'auth:admin'] that's mean you need to login default guard and admin guard. if you need only login admin guard, ['auth:admin']

Laravel grouping routes what is best prefix or middleware

When I start thinking grouping my routes and check the documentation. I lost there. There are too many things like prefix, middleware etc.
What is the best way to group routes?
Route::group(['middleware' => 'admin'], function () {});
Route::group(['prefix' => 'admin'], function () {});
Route::group(['namespace' => 'admin'], function () {})
Which approach is best? And why? When to use what approach?
Wait. Prefix and middleware are two different things
prefix is a way to Prefix your routes and avoid unnecessary typing e.g:
Route::get('post/all','Controller#post');
Route::get('post/user','Controller#post');
This can be grouped using prefix post
Route::group(['prefix' => 'post'], function(){
Route::get('all','Controller#post');
Route::get('user','Controller#post');
})
In the other hand, Middleware :
Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.
For example using last example now i want the users to be authenticated in my post routes. I can apply a middleware to this group like this:
Route::group(['prefix' => 'post', 'middleware' => ['auth']], function(){
Route::get('all','Controller#post');
Route::get('user','Controller#post');
})
You should check the docs to get more informed.
https://laravel.com/docs/5.5/middleware
https://laravel.com/docs/5.5/routing#route-groups
Both are different But to use both at the same time Best technique for grouping route middleware and prefix your route avoid unnecessary typing
Route::group(['prefix' => 'admin','middleware' => ['auth:admin']], function() {
Route::get('dashboard','AdminController#dashboard');
});
It may not be related to the current question, but if anyone is wondering how to use grouping prefix and middleware as well as controller in a scenario where you need auth check and then need a prefix to avoid repeat typing for the specific controller group, you may try the following way.
Route::middleware(['auth', 'verified'])
->controller(\App\Http\Controllers\AdminController::class)
->prefix('dashboard')->group(function() {
Route::get('/', 'adminIndex')->name('admin.index');
});
Or,
Route::group(['middleware' => ['auth', 'verified'], 'prefix' => 'dashboard'], function () {
Route::controller(\App\Http\Controllers\AdminController::class)->group(function (){
Route::get('/', 'adminIndex')->name('admin.index');
});
});

Protecting routes with LDAP

I am slightly confused by something. For Authentication, I am using LDAP, more specifically this https://github.com/SaschaDens/ldap-connector
That LDAP library I am using essentially works on top of Laravels Authentication Facade.
Everything is fine, I can log in and out now using LDAP. When logged in however, I have an update users buttons. This essentially uses LDAP to get
all the groups a user is apart off. So I have three tables,
users
groups
users_groups
When the button is pushed, I add all users to the users table. I then add all unique groups to the groups table. The last table users_groups is essentially a pivot table which links a users_id to a groups_id.
By the end of this, I can see that I am for instance apart of 3 groups, one of which is the admin group. I can also see all members of this group by doing this
$group = Group::where('groupName', 'admin')->first();
$users = $group->user;
Now there are some routes I only want to make available to admin users. I can see in Kernel.php there is the following
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
];
At the moment I am only using auth to make sure the user is logged in. Obviously I do not have an admin one set up yet, and I think the way I am doing it there could be a problem because I am creating my own groups table.
How would I go about blocking access to a particular route to only users who are apart of the admin group?
Thanks
You can do this by creating a new route middleware.
1) create middleware class
php artisan make:middleware AdminMiddleware
2) Add authentication logic to you AdminMiddleware class
if(Auth::user()->inGroup('GROUPNAME'))
{
return $next($request);
}
else
{
return view('auth.login')->withErrors('You are not logged in');
}
3) Add the new middleware to your $routeMiddleware
'admin' => 'App\Http\Middleware\AdminMiddleware',
4) Add the middleware alias to the routes you wish to protect
Route::get('admin', [
'as' => 'admin',
'middleware' => 'admin',
'uses' => 'AdminController#getAdminPage'
]);

Apply multi-middleware for same action in Laravel 5

I have 2 roles: admin and agent, and I have a search page. I want to allow 2 roles to access this page.
So if an admin logs in then it can access the search page, and if an agent logs in then it can access the search page as well.
In the route.php file I am doing the following:
Route::group(['middleware' => 'admin'], function(){
Route::post('customer/search', 'CustomersController#search');
});
Route::group(['middleware' => 'agent'], function(){
Route::post('customer/search', 'CustomersController#search');
});
In this case an admin can not access the search page.
And if reverse the middleware like this:
Route::group(['middleware' => 'agent'], function(){
Route::post('customer/search', 'CustomersController#search');
});
Route::group(['middleware' => 'admin'], function(){
Route::post('customer/search', 'CustomersController#search');
});
the agent can not access the search page.
So, how can I allow the admin and agent roles to both access the search page.
If each middleware checks its own role (if the user is an admin and respectively an agent), then the first executed middleware will always restrict access to the last in one of the cases. There's no way around that if you do a separate check in each middleware. You perhaps need a common middleware that validates all roles that are allowed to access the search route. So something like this:
Route::group(['middleware' => 'searchRoles'], function()
{
Route::post('customer/search', 'CustomersController#search');
});

Resources