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'
]);
Related
I've been trying forever to figure out how to create separate login views for different types of users in Laravel. I have one User model and then a roles table and role_users table. I do need to have users pick how they would like to login (i.e. as an Advisor, HR Admin, Employee). For example, one user can have both the Employee and HR Admin Role.
Here is what I attempted, using Laravel 7:
Install the Auth scaffolding
Create view called advisor-login by copying the login view that comes with basic Laravel Auth
Create AdvisorLoginController by copying the LoginController that comes with basic Laravel Auth
Create advisor-login route that directs to the AdvisorLoginController. Update the action in the advisor-login view to go to this route
In the AdvisorLoginController, we have:
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
The "protected $redirectTo = RouteServiceProvider::HOME;" part is relatively straightforward as I could modify this to go to the Advisor Dashboard after logged in.
But the AuthenticatedUsers trait presents a problem. I went down this rabbit hole and couldn't get out. I tried to copy the AuthenticateUsers files from with the Laravel/UI package and create an AuthenticateAdvisors trait, but this became a mess.
Am I missing an easy fix here?
It can be done by providing multiple guards, for instance, one guard for admin and another for the user or customer, Then you should create a separate login controller in a different namespaces(it is recommened to be in different namespaces).
First, create a different guard for each in config/auth.php like below(you might want to use differnt driver in guard)
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admins' => [
'driver' => 'passport',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
you should group your routes by providing namespaces for different user types
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function () {
//your route goes here!
});
by grouping routes you can have multiple logins form.
for authenticating the different user types you can create a different middleware for each type like admin for instance and
<?php
namespace App\Http\Middleware;
use Closure;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (!auth()->user()->isAdmin()) {
return response()->json(['message' => 'You have no rights'], 403);
}
return $next($request);
}
}
then add the admin middleware to your routes for validatiating the roles and other stuff. like below
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function () {
//your route goes here!
Route::group(['prefix' => 'dashboard', 'middleware' => ['auth','admin']], function () {
//your route goes here!
});
});
In my opinion wanting to create a specific login page for each user profile is not very optimal. there can be only one page but the access to functionality is managed by ACL. There may be an administration area where you can define and assign roles
I'm trying to create a login page with laravel web route. When user login, a session record will be saved to database. But in session table, user_id always get null value.
I've found that in Illuminate\Session\DatabaseSessionHandler, function userId() always return null. It's because I set default guard for api. This is my config/auth.php:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
When I change default guard to web, column user_id in database has value is authorized user id. I don't want to change my default guard to web.
How can I set guard driver for session? Is there something like Auth, we can use Auth::guard('web').
Thanks
Typically, API's are not associated with keeping session state between requests.
You can always add additional groups with seperate guards to the same routes and use them according to your needs. E.g.
Route::group(['middleware' => 'auth:api'], function () {
Route::post('/user', 'UserController#apiUser');
}
Route::group(['middleware' => 'auth'], function () {
Route::post('/user', 'UserController#index');
}
and then seperately reference
$user = auth('web')->user();
or
$user = auth('api')->user();
Read here for a Laravel API implementation using Passport. You may also want to consider Laravel Sanctum which offers support for API token generation for your users.
Lets say I have the following guards:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'users',
],
],
I login to my app as a normal user using the default 'web' guard and to access the authenticated user I can use the following: $user = Auth::user();
public function __construct()
{
$this->middleware('auth');
}
public function edit()
{
$user = Auth::user();
}
At the same time I also login to the same app as an admin using the 'admin' guard and in admin controllers I have the following middleware and to access the authenticated admin I do the following: Auth::guard('admin')->user()
public function __construct()
{
$this->middleware('auth:admin');
}
public function edit()
{
$user = Auth::guard('admin')->user();
}
The question is do I need to specify the guard each time to access the admin user - I've noticed once I've authenticated in constructor using $this->middleware('auth:admin') I no longer need to specify the guard to access the authenticated user inside other controller methods? Is this correct behaviour
As far as I can see, your admin guard isn't doing anything different to the web guard. It's using the same driver and the same provider. So there is absolutely no difference between using Auth::user() and Auth::guard('admin')->user().
If you do decide to implement a custom driver (different to the session driver) for your admin guard, you'll need to use Auth::guard('admin')->user() (or set your guard as default) when accessing the authenticated user. Otherwise, Auth::user() will look for user details in the session.
As a side note, the default session driver caches the user instance on first retrieval which in your case is when the request hits the auth middleware. Subsequent calls to Auth::user() or Auth::guard('admin')->user() are handled by returning the user instance from cache.
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']
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