I am trying to authenticate users and admin form user table and admin table respectively. I am using the User model as provided by laravel out of the box and created the same for Admin. I have added a guard key and provider key into auth.php.
Guards
'guards' => [
'user' =>[
'driver' => 'session',
'provider' => 'user',
],
'admin' => [
'driver' => 'session',
'provider' => 'admin',
],
],
Providers
'providers' => [
'user' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
]
],
Routes
Route::group(['middleware' => ['web']], function () {
// Login Routes.
Route::get('/admin/login','AdminAuth\AuthController#showLoginForm');
Route::post('/admin/login','AdminAuth\AuthController#login');
Route::get('/admin/logout','AdminAuth\AuthController#logout');
// Registration Routes.
Route::get('admin/register', 'AdminAuth\AuthController#showRegistrationForm');
Route::post('admin/register', 'AdminAuth\AuthController#register');
Route::get('/admin', 'AdminController#index');
});
I have created a directory called AuthAdmin where Laravel's default AuthController.php and PasswordController.php files are present. (Namespace Modified accordingly)
First of all, in Laravel's docs mentioned that how to specify custom guard while authenticating like this which isn't working.
There's another method mentioned in Laravel's docs to use a guard which is not working too.
It would be beneficial if someone could resolve the issues and correct me if I am wrong.
After lots of digging and lots of questions & answers I have finally managed to work Laravel 5.2 Multi Auth with two table, So I'm writing Answer of my own Question.
How to implement Multi Auth in Laravel 5.2
As Mentioned above.
Two table admin and users
Laravel 5.2 has a new artisan command.
php artisan make:auth
it will generate basic login/register route, view and controller for user table.
Make a admin table as users table for simplicity.
Controller For Admin
app/Http/Controllers/AdminAuth/AuthController
app/Http/Controllers/AdminAuth/PasswordController
(note: I just copied these files from app/Http/Controllers/Auth/AuthController here)
config/auth.php
//Authenticating guards
'guards' => [
'user' =>[
'driver' => 'session',
'provider' => 'user',
],
'admin' => [
'driver' => 'session',
'provider' => 'admin',
],
],
//User Providers
'providers' => [
'user' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
]
],
//Resetting Password
'passwords' => [
'clients' => [
'provider' => 'client',
'email' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
'admins' => [
'provider' => 'admin',
'email' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
],
route.php
Route::group(['middleware' => ['web']], function () {
//Login Routes...
Route::get('/admin/login','AdminAuth\AuthController#showLoginForm');
Route::post('/admin/login','AdminAuth\AuthController#login');
Route::get('/admin/logout','AdminAuth\AuthController#logout');
// Registration Routes...
Route::get('admin/register', 'AdminAuth\AuthController#showRegistrationForm');
Route::post('admin/register', 'AdminAuth\AuthController#register');
Route::get('/admin', 'AdminController#index');
});
AdminAuth/AuthController.php
Add two methods and specify $redirectTo and $guard
protected $redirectTo = '/admin';
protected $guard = 'admin';
public function showLoginForm()
{
if (view()->exists('auth.authenticate')) {
return view('auth.authenticate');
}
return view('admin.auth.login');
}
public function showRegistrationForm()
{
return view('admin.auth.register');
}
it will help you to open another login form for admin
creating a middleware for admin
class RedirectIfNotAdmin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = 'admin')
{
if (!Auth::guard($guard)->check()) {
return redirect('/');
}
return $next($request);
}
}
register middleware in kernel.php
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\RedirectIfNotAdmin::class,
];
use this middleware in AdminController
e.g.,
middleware('admin');
}
public function index(){
return view('admin.dashboard');
}
}
That's all needed to make it working and also to get json of authenticated admin use
`Auth::guard('admin')->user()`
**Edit - 1**
We can access authenticated user directly using
`Auth::user()`
but if you have two authentication table then you have to use
Auth::guard('guard_name')->user()
for logout
Auth::guard('guard_name')->user()->logout()
for authenticated user json
Auth::guard('guard_name')->user()
##Edit 2
Now you can download Laravel 5.2 Multiauth implemented Project http://imrealashu.in/code/laravel/multi-auth-with-laravel-5-2-2/
In case this helps anyone, and this may just be due to my lack of understanding of middleware, here's what I had to do to get this working (in addition to the steps taken by #imrealashu)...
In route.php:
Route::get('/admin', [
'middleware' => 'admin',
'uses' => 'AdminController#index'
]);
This is in the web middleware group. Before this I tried putting it in a separate admin middleware group and even in an auth:admin group but this didn't work, it only worked for me when I specified the middleware as admin on the route itself. I have no idea why this is but I hope it saves others from pulling their hair out like I did.
It's very easy in laravel 5.6. Just go to config/auth.php and add this line in providers array:
'admins' => [
'driver' => 'database',
'table' => 'admin_table'
]
Note that we used database for driver not eloquent.
Now add this to guards array:
'admin_guard' => [
'driver' => 'session',
'provider' => 'admins'
]
Now we're done! Use this when working with admins table:
Auth::guard('admin_guard')->User();
Cheers.
Related
I have created two guards.Admin and Manager. To create authentication for admin I have followed https://blog.pusher.com/laravel-jwt/ this blog and it worked well. For my 2nd guard authentication middleware route manager not working. It says Manager not found.So I put only admin in group route and for manager I have declared the guard inside of auth method but It still not working. It can't find my model to store so I had to post the row data inside phpmyadmin manually and checked the login if it works or not but it's still not working. Returns the error part.
Api.php
Route::post('/manager/register', [App\Http\Controllers\ManagerUserController::class,'register']);
Route::post('/manager/login', [App\Http\Controllers\ManagerUserController::class,'authenticate']);
Route::get('open', [ManagerDataController::class,'open']);
Route::group(['middleware' => ['jwt.verify']], function() {
Route::get('user', [ManagerUserController::class,'getAuthenticatedUser']);
Route::get('closed', [ManagerDataController::class,'closed']);
});
Route::group(['middleware'=>'admin'],function($router){
Route::post('/admin/register', [App\Http\Controllers\AdminUserController::class,'register']);
Route::post('/admin/login', [App\Http\Controllers\AdminUserController::class,'authenticate']);
Route::get('open', [AdminDataController::class,'open']);
Route::group(['middleware' => ['jwt.verify']], function() {
Route::get('user', [AdminUserController::class,'getAuthenticatedUser']);
Route::get('closed', [AdminDataController::class,'closed']);
});
managerController:
public function authenticate(Request $request)
{
$credentials = $request->only('username', 'password');
if (! $token = auth()->guard('manager')->attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 400);
}
return response()->json(compact('token'));
}
auth.php
'defaults' => [
'guard' => 'admin',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'jwt',
'provider' => 'admins',
],
'manager' => [
'driver' => 'jwt',
'provider' => 'managers',
],
]
Another problem is if I set web for default guard then admin guard not working but if I put admin as default guard then it works. It this work like this then how can I use multi jwt authentication cause theres only single default guard exists!
i use this package :
https://github.com/spatie/laravel-permission/tree/v2
code :
$user=User::find(2);
$user->assignRole('admin');
and when i assign admin role to user I'm dealing with this error
There is no role named admin.Spatie\Permission\Exceptions\RoleDoesNotExist
this is my default guard in auth.php :
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
this is my roles table :
this is my role_has_permission table
and this is my permission table :
just add this protected property to your user model(or whatever model you are using for assigning permissions and roles).
protected $guard_name = 'api';
Add one of the following to your User model:
public $guard_name = 'api';
Or:
public function guardName()
{
return 'api';
}
As a convention it's best to do configurable things in the config file.
The problem with your code is the order of arranging your guards, just re-arrange as seen below.
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
...
Once this is done, you don’t need to add protected $guard_name = 'api'; to your User model, ensure to run php artisan config:clear
Ref: Saptie Laravel Permisions
friends! I found solution for this problem but first of all, i illustrate why this problem happened. As you know, Laravel read the codes from top to bottom and from left to right. Moreover when we want from laravel fresh all data by command
php artisan migrate :fresh --seed
It clears all this data and the problem begin. By other word, when assign Role command to check for new role it fails because all data is cleared before it access to those data. To avoid this we should set Role seeder class before Admin seeder class in database seeder
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
$this->call([RoleSeeder::class, AdminSeeder::class]);
}
}
Add this to your user model
use Spatie\Permission\Traits\HasRoles;
and in a user model class
use HasRoles;
Here is a reference
Complete example
This worked for me:
$role = Role::create(['guard_name' => 'admin', 'name' => 'manager']);
Can we use laravel passport with different guards to authenticate APIs for two different types of users.
For example we have driver app for driver user and vendor app for vendor user. Both have their different models Driver and Vendor.
How can we use different guards to authenticate both types of users using Laravel Passport?
I managed to create multiple auths (with laravel/passport) by using a simple middlware.
Step 1: config/auth.php
Add your user classes to providers
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'basic_users', // default
],
],
...
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin_users' => [
'driver' => 'eloquent',
'model' => App\AdminUser::class,
],
'basic_users' => [
'driver' => 'eloquent',
'model' => App\BasicUser::class,
],
],
Clean the cache via CLI
php artisan config:cache
Step 2: Create middleware
php artisan make:middleware AdminUserProvider
Open the newly created middleware in app/Http/Middleware and update the hand method like below
public function handle($request, Closure $next)
{
config(['auth.guards.api.provider' => 'admin_users']);
return $next($request);
}
Step 3: Register your middleware
Add the newly created middleware to $routeMiddleware
protected $routeMiddleware = [
...
'auth.admin' => \App\Http\Middleware\AdminUserProvider::class,
];
and make sure it's at the top of $middlewarePriority
protected $middlewarePriority = [
\App\Http\Middleware\AdminUserProvider::class,
...
];
Step 4: Add middleware to route
Route::group(['middleware' => ['auth.admin','auth:api']], function() {
Step 5: LoginControllers (AdminUserController & BasicUserController)
public function login()
{
$validatedData = request()->validate([
'email' => 'required',
'password' => 'required|min:6'
]);
// get user object
$user = AdminUser::where('email', request()->email)->first();
// do the passwords match?
if (!Hash::check(request()->password, $user->password)) {
// no they don't
return response()->json(['error' => 'Unauthorized'], 401);
}
// log the user in (needed for future requests)
Auth::login($user);
// get new token
$tokenResult = $user->createToken($this->tokenName);
// return token in json response
return response()->json(['success' => ['token' => $tokenResult->accessToken]], 200);
}
In summary:
The login controllers use Eloquent models to get the user object and then log the user in through Auth::login($user)
Then for future requests that need authentication, the new middleware will change the api auth guard provider to the correct class.
Edit: Passport now has support for multiple guard user providers. Please refer the following links for more infos:
Multiple Authentication Guards
Support For Multiple Guards
Old answer (I would not recommend it)
Here is an example of auth.php and api.php to start with
config/auth.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'driver-api' => [
'driver' => 'passport',
'provider' => 'drivers',
],
'vendor-api' => [
'driver' => 'passport',
'provider' => 'vendors',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'drivers' => [
'driver' => 'eloquent',
'model' => App\Driver::class,
],
'vendors' => [
'driver' => 'eloquent',
'model' => App\Vendor::class,
],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
'drivers' => [
'provider' => 'drivers',
'table' => 'password_resets',
'expire' => 60,
],
'vendors' => [
'provider' => 'vendors',
'table' => 'password_resets',
'expire' => 60,
],
],
];
routes/api.php
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
*/
Route::group(['namespace' => 'Driver', 'prefix' => 'driver/v1', 'middleware' => 'auth:driver-api'], function() {
// define your routes here for the "drivers"
});
Route::group(['namespace' => 'Vendor', 'prefix' => 'vendor/v1', 'middleware' => 'auth:vendor-api'], function() {
// define your routes here for the "vendors"
});
You have to modify this files:
File: vendor\laravel\passport\src\Bridge\UserRepository.php
Copy/Paste getUserEntityByUserCredentials to make a duplicate of it and name it getEntityByUserCredentials
Then, in the new duplicated function, find the below:
$provider = config('auth.guards.api.provider');
And Replace it with:
$provider = config('auth.guards.'.$provider.'.provider');
File: vendor\league\oauth2-server\src\Grant\PasswordGrant.php
in : validateUser method add after $username and $password :
$customProvider = $this->getRequestParameter('customProvider', $request);
if (is_null($customProvider)) {
throw OAuthServerException::invalidRequest('customProvider');
}
And this instead of the original line
$user = $this->userRepository->getEntityByUserCredentials(
$username,
$password,
$this->getIdentifier(),
$client,
$customProvider
);
After doing this you'll be able to pass an extra key/value pair to your access token request, like for example:
grant_type => password,
client_id => someclientid
client_secret => somesecret,
username => someuser,
password => somepass,
client_scope => *,
provider => driver-api // Or vendor-api
I hope this will be helpful for you
After spent time I have found that in Laravel 7 there is no custom code required except some configuration. For details please check this answer I have tested & implemented in my projects
Multi Auth with Laravel 5.4 and Passport
You don't necessarily need to change config for each request.
You need a client for each guard. After creating clients by running
passport:install
Make sure you specified provider field in database. It should be same value as auth.providers config.
After creating clients and guards, use following code when creating an access token.
App::clearResolvedInstance(ClientRepository::class);
app()->singleton(ClientRepository::class, function () {
return new ClientRepository(User::CLIENT_ID, null); // Client id of the model
});
Make sure you specified provider in oauth_clients table.
I'm using laravel and want to use the built-in authentification system.
One should be able to login in into my app using his/her ldap account. I don't want to copy the ldap users to a local database.
So I wrote a custom UserProvider where I log in into the ldap server:
class LdapAuthProvider implements UserProvider
{
public function retrieveByCredentials (array $credentials)
{
// try to connect with given username
$ldap = new \Adldap\Adldap();
$ldap->addProvider ( [
// config stuff based on $credentials ...
] );
try {
$ldap->connect();
return new \App\User (['id': $credentials['username']]);
}
catch (\Adldap\Auth\BindException $e) {
return NULL;
}
}
And then registered it in the AuthServiceProvider in the boot method
Auth::provider ('ldap', function($app)
{
return new LdapAuthProvider;
});
When I call Auth::attempt from my LoginController with correct username and password, the function returns true. But after redirecting to another page, Auth::check returns false, so it is not stored in the session that I have logged in successfully.
My config/auth.php looks like this
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'ldap',
'model' => App\User::class,
],
Storing data manually in the session using Session::put() works fine.
What do I have to do in order to keep the user logged in after redirect to another page?
Please, can anybody explain how to implement multiple authentication guards in Lumen framework? Currently, I have two authenticatable models: Users and Clients. I'm using a custom implementation of JWT. A User has client_id and user_id fields in their token payload. While a Client only has client_id. Based on this I need to determine who came to me: client, user or guest (without a token).
auth.php
'guards' => [
'client' => [
'driver' => 'token',
'provider' => 'clients',
],
'user' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'clients' => [
'driver' => 'eloquent',
'model' => App\Client::class,
],
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
],
AuthServiceProvider.php
public function boot()
{
$this->app['auth']->viaRequest('token', function ($request) {
$access_token = HelperClass::getTokenFromHeader($request->headers->get('Authorization'));
if ($access_token) {
$tokendata = JWT::decode($access_token, getenv('TOKEN_SECRET'), array('HS256'));
if ($tokendata->user_id) {
return User::find($tokendata->user_id);
}
return Client::find($tokendata->client_id);
}
});
}
routes.php
$app->get('/api/{item_id:\d+}', ['middleware' => 'auth:user', 'uses' => 'App\Http\Controllers\ItemController#get']);
I want to allow only Users to access this route, but Clients successfully pass this middleware too: Auth::check() returns true and Auth::user() returns an instance of App\Client 😕
Another situation: what if for some routes I want to allow both: clients and users. For another routes - guests, clients and users.