How to use laravel's Auth class in different table? - php

I created a simple login and registration in my page and I also added some new columns in the default users table. Now my problem is I have another table named as admin and the default Laravel's Auth table is users. How can I implement the same functionality in my table?
In the Users model it has the declaration for the table name
protected $table = 'users';
Can you give me an example how can I use the default laravel's auth class?
Thats all thanks. :-)

Laravel takes default users table for an application. For a change of laravel authentication different table relevant table name, we need to make a small change in authentication file of config.
Go to
config/auth.php
'providers' => [
// 'users' => [
// 'driver' => 'eloquent',
// 'model' => App\User::class,
// ],
'users' => [
'driver' => 'database',
'table' => 'user',
],
],

Do you hear about Multiauth in laravel. in this library there are two or more type user can login in one laravel application. In our case there are two type user Admin and Public that means User right.
Both forgot password and reset password functionality works separately in one application.
After install this library have have one step like below.
'multi' => [ 'admin' => [ 'driver' => 'database', 'table' => 'admin', 'email' => 'client.emails.password' ], 'users' => [ 'driver' => 'database', 'table' => 'users', 'email' => 'client.emails.password', ] ],
change your Auth.php file code with this one.
installation
Firstly you want to include this package in your composer.json file.
"require": {
"sboo/multiauth" : "4.0.*"
}
Now you'll want to update or install via composer.
composer update
Usage
Everything is done the exact same way as the original library, the one exception being that all method calls are prefixed with the key (account or user in the above examples) as a method itself.
Auth::admin()->attempt(array(
'email' => $attributes['email'],
'password' => $attributes['password'],
));
Auth::client()->attempt(array(
'email' => $attributes['email'],
'password' => $attributes['password'],
));
Auth::admin()->check();
Auth::client()->check();
Here is your library

I don't think the best way is to duplicate your table. I would extend users table with a role field that indicates if the user is a standard one or an admin. This way, you can keep the same code and add the ADMIN functionality that you are looking for.
If you NEED to do that and you are using Laravel 4, maybe you can use this plugin:
https://github.com/ollieread/multiauth/
Also in this thread you have code that implements Auth in different tables:
https://gist.github.com/danielcoimbra/64b779b4d9e522bc3373
But I strongly suggest to integrate both tables in one with an Admin flag/field

Related

Laravel 6 Multiple Authentications (Login Forms)

I have a problem that I'm facing with Laravel 6 LTS version. I have 3 different controllers: AdminController (/admin), ScheduleController (/schedule) and ClientController (/client). Each of those controller should authenticate different database table of users. For /admin it uses 'users' table, for /schedule it uses 'companies' table and for /client it uses 'clients' table. Technically, you should be able to login to each "controller" without the worry of colliding with other controllers. For instance, you can be logged in to /admin and also to /client and /schedule (separate login form for each). How should I go about this? Can someone point me in the right direction? Is this possible with Laravel?
Thanks
You can set different user providers in config/auth.php
'providers' => [
'user' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
Reference

Laravel Passport - Multiple guards issue

Thank you in advance,
I want multiple laravel passport guards as my system has 2 user types, 1) Admin, 2) Normal User.
for both, I have separate routes and authentication modules(Login, register, logout, etc). so I need a separate passport guard for the API authentication. a few of the codes I added as below
config/auth.php looks like below
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
'api-admin' => [
'driver' => 'passport',
'provider' => 'admins',
'hash' => false,
]
],
Here i defined 2 guards for admin and user
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'table' => App\Models\Admin::class,
],
],
Here i defined 2 providers for admin and user
Now i am creating token like
$tokenResult = $user->createToken('TOKEN_DEMO');
$token = $tokenResult->token;
$token->save();
$accessToken = $tokenResult->accessToken;
It is generating well as expected for admin user with user_id = 1 (As an example consider user_id = 1)
this is about generating token for the admin user
the same way normal user logged in and generating token as same as above then this will also generate the token for the user with user_id = 1 in oauth_clients table
The table looks like as mentioned in the screenshot
The concern is that if the normal user logged out then automatically admin user's token will be destroyed as both's user_id is 1 in oauth_clients table while guards is different for both
Please help me out for the same
It's also a security issue as your user with same id as admin can pass admin authentication middleware.
Following method is the cleanest workaround I've found.
You have to use different clients for your guards.
You have to run
passport:install
two times if you have two guards using Passport. it will generate two clients.
In new versions of Passport(I think after release of Laravel 8) when you are creating a client it asks you for a provider(Defined in auth.providers config). Each provider needs one client. If you are using old versions you can manually assign providers in oauth_clients table.
Now when generating token you have to specify client id.
In older versions you could do this by changing a public property of one of Passport classes but now you should register ClientRepository again.
App::clearResolvedInstance(ClientRepository::class);
app()->singleton(ClientRepository::class, function () {
return new ClientRepository(User::CLIENT_ID, null); // You should give the client id in the first parameter
});
$token = $user->createToken('TOKEN-EXAMPLE');
$accessToken = $token->accessToken;
Now if you check your access tokens table you can see that client ids are different.
Everything is fine now.
You mentioned there might be an issue with revoking tokens but I believe even in your case(using same client and not specifying providers) if you revoke a user token with same id as admin, admin's token will still remain. Revoking user token:
$user = Auth::guard('user-api')->user();
$user->token()->revoke();
does the guard apear anywhere on the token? or do tokens only have scopes? and if so, why would you use guards when you can use scopes...
good day!
[Edit]
in my case, im using roles and permissions to write my scopes... roles and permissions are guard based and a permission or role with a admin guard cannot be assigned to a user unless we add the 'admin' key with (in my case) 'passport' drive and 'user' provider...

Separate authentication for front-end user and admin in cakephp 3.x

We are working on a project where are 4 roles. But in cakephp 3.x Auth component holds authenticate user data in session with Auth.User indexing using
$this->Auth->setUser($user);
Due to this we are not able to access front-end user account from admin panel for some purpose, because of when we login to front-end user from admin panel, front-end login action performs and over write of session value.
So if there is any process to handle this please suggest us.
Thank you in advance.
As well I have understood that you are not using prefix to manage back-end and front-end user then may be you worked with separate folder structure for back-end, May I right?
You are right that $this->Auth->setUser($user); always holds session with Auth.User indexing. So you need to write different session indexing for back-end, and you can do it as follow :
For back-end user authentication :
**
$this->loadComponent('Auth', [
'authorize' => ['Controller'], // Added this line
'loginRedirect' => [
'controller' => 'Users',
'action' => 'dashboard',
'prefix' => 'admin_panel'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login',
'prefix' => 'admin_panel'
],
'storage' => [
'className' => 'Session',
'key' => 'Auth.Admin',
]
]);
**
Here you can pass your desired index in 'storage' array key value.
I think it'll works for you.
Check out the section Authentication and Authorization in this curated list of CakePHP Plugins.
You could, for example, use dereuromarks TinyAuth Plugin to authorize your users and configure what they are able to see.
This way you can use the same authentication (be aware of the differences between Authentication and Authorization) and the same users table, which will prevent the Session conflict you mentioned.
The Auth component overwrite the previous session because it store the session in Auth.users all the time so we have to change the session key for different role.
If you are using URL prefix for the different roles to access then you can do like this.
AppController.php
public function beforeFilter(Event $event)
{
if($this->request->params['prefix']){
$this->Auth->config('storage', [
'key'=>'Auth.'.$this->request->params['prefix'],
'className'=>'Session'
]);
}
return parent::beforeFilter($event); // TODO: Change the autogenerated stub
}
This will create different roles in Auth as you required.
The session will be like this
[
'Auth'=>[
'User'=>['id'=>''],
'Admin'=>['id'=>''],
]
]
Tested it, working great for me.

CakePHP 3.2 - Specify different datasource for session handler

I am having an issue specifying a different datasource to use in a custom session handler inside config/app.php. Here are the relevant bits:
config/app.php
<?php
return [
... ,
'Datasources' => [
'default' => [...],
'test' => [...],
'session' => [...]
],
'Session' => [
'defaults' => 'database',
'ini' => ['session.cookie_domain' => '.example.com'],
'handler' => [
'engine' => 'CustomSessionHandler', // file and class name of custom handler
'model' => 'sessions' // table name
]
]
];
CustomSessionHandler.php is a copy of the default DatabaseSession.php with a few customisations in the query building to work with our existing sessions table schema.
Right now, it's trying to use the 'default' datasource, and as you might guess, I'm trying to get it to use the 'session' datasource. However I can't find any information on how to do that.
Any assistance is greatly appreciated!
The session handler only knows about the model, respectively the table class, and it shouldn't really know more than that.
So what you could do is configure that table class to use a non-default connection. If you don't have a concrete SessionsTable class yet, create one, and override Table::defaultConnectionName(), like
public static function defaultConnectionName()
{
return 'session';
}
See also Cookbook > Database Access & ORM > Table Objects > Configuring Connections

How to use orchestral/tenanti in Laravel 5 to build a multi tenant application with multiple databases?

I am trying to build and application using Laravel 5. It is supposed to be a multi tenant database architecture using multiple databases. My employer requires this for security purposes.
I have tried manually managing the main DB migrations and the Tenant migrations but failed. So I decided to take the help of a Laravel specific package which is supposedly what I require.
Tenanti provides a way to have my purpose solved but the problem is that me being a novice developer, am not able to fully understand how to use it in my application.
I have installed it correctly I believe doing:
composer require "orchestra/tenanti=~3.0"
Adding these providers and aliases in the config app file:
'providers' => [
// ...
Orchestra\Tenanti\TenantiServiceProvider::class,
Orchestra\Tenanti\CommandServiceProvider::class,
],
'aliases' => [
'Tenanti' => Orchestra\Support\Facades\Tenanti::class,
],
Finally publishing the config and tweaking it according to the documentation for multiple databases:
php artisan vendor:publish
return [
'drivers' => [
'user' => [
'model' => App\User::class,
'migration' => 'tenant_migrations',
'path' => database_path('tenanti/user'),
],
],
];
At this point I am still blurry what to do next?
My doubts are as follows:
Where will the migration files be generated and stored? I mean there are two kinds of databases in my application obviously. One set of files is for the main DB which will store all the tenant information and the other files will be for the tenant DB. So how and where will these be stored?
I see the word 'driver' a lot in the documentation but I am not sure what driver is exactly.
How will I handle the authentication for the application? I mean whenever a tenant logs in, I will have to make sure the connection to the database changes dynamically. How will I accomplish this?
I tried to go through the repository of the package itself and make sense of the code inside but in vain. I am not very good when it comes to design patters like facades, command bus, service provider and so on, which is why I am not able to understand the flow of the package or make sense of it.
I tried to run some of the artisan commands which come with the package like:
php artisan tenanti:install {driver}
php artisan tenanti:make {driver} {name}
But I am getting an error like so:
[InvalidArgumentException] Database connection
[tenants] is not available.
Where can I find the resources to understand how to proceed with this?
+1 to #morphatic answer, it quiet accurate on most of the stuff.
Migration
One set of files is for the main DB which will store all the tenant information and the other files will be for the tenant DB. So how and where will these be stored?
For your main database you should be able to use the default database/migration and utilize php artisan make:migration and php artisan migrate.
Tenanti however will use the migration path set under the "driver" configuration. e.g:
'path' => database_path('tenanti/user'),
In this case the migration will be created/migrated from database/tenanti/user (you can choose other folder and it will use that folder). Once you set this up you can create new migration file for the user tenant via php artisan tenanti:make user create_blogs_table (as an example) and run migration via php artisan tenanti:migrate user (see the similarity between Laravel migration command and Tenanti?).
Driver
Driver is just the grouping of a tenant, you maybe grouping it by users, companies, or team etc. And there is possibility that you may require more than one type of group per project, otherwise most of the time you only be using single "group" or "driver".
Authentication or Accessing DB
How will I handle the authentication for the application? I mean whenever a tenant logs in, I will have to make sure the connection to the database changes dynamically. How will I accomplish this?
First of all, you need to consider how you're planning to distinguish each tenant. Most of the time I would see people tend to opt for subdomain. So in this case you need to check if the subdomain belongs to any of the user (by querying the main database) using a middleware and then connect to the database that belongs to the user.
Tenanti doesn't manage that part of the process, because everyone has different style on that aspect, but we do provide a code to dynamically connect to your database tenant from a base database configuration.
Let say you have the following config:
<?php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => 'primary',
'connections' => [
'primary' => [
//
],
'tenants' => [
'driver' => 'mysql',
'host' => 'dbhost', // for user with id=1
'username' => 'dbusername', // for user with id=1
'password' => 'dbpassword', // for user with id=1
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
],
],
'migrations' => 'migrations',
'redis' => [ ... ],
];
You can follow the step available in https://github.com/orchestral/tenanti#multi-database-connection-setup and add the following code.
<?php namespace App\Providers;
use Orchestra\Support\Facades\Tenanti;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Tenanti::setupMultiDatabase('tenants', function (User $entity, array $template) {
$template['database'] = "tenant_{$entity->getKey()}";
return $template;
});
}
}
This would ensure that you be using tenant_1 database for user=1, tenant_2 database for user=2 and so on.
So how does Tenanti detect which user if active?
This is where you need to add logic in your middleware.
$user = App\User::whereSubdomain($request->route()->parameter('tenant'))->first();
Tenanti::driver('user')->asDefaultDatabase($user, 'tenants_{id}');
I've never used this package, but using the code you submitted above here's what I think is probably close to the right solution. You will probably still need to play with some of these values to get them correct:
Migration Paths
Since you're using the multi-database configuration, I believe you should be able to keep your migrations in the normal location, i.e. database/migrations. Tenanti will then create an exact replica of the database for each tenant in a different database. However, when you run php artisan tenanti:install user it might actually create a folder under database/ that indicates where you should put your migrations.
What is a "driver"?
The driver describes whether Tenanti will use a single or multiple databases, what models to use for determining different tenants, and where to store migrations. It is what you identified in the Tenanti config file you used above.
Database Connection Selection
You need to update config/database.php as follows. In a normal Laravel app, you would have the DB connection setup as follows:
<?php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'sqlite' => [ ...DB connection info... ],
'mysql' => [ ...DB connection info... ],
'pgsql' => [ ...DB connection info... ],
'sqlsrv' => [ ...DB connection info... ],
],
'migrations' => 'migrations',
'redis' => [ ... ],
];
However, in the case of Tenanti multi-database setup, you need to add in different connection info for each tenant's database. To do this you would add a new level to your database.php config file (this example assumes you're using mysql, but you could use any DB, or even different database engines for different tenants):
<?php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'tenants' => [
'user_1' => [
'driver' => 'mysql',
'host' => 'dbhost', // for user with id=1
'database' => 'dbname', // for user with id=1
'username' => 'dbusername', // for user with id=1
'password' => 'dbpassword', // for user with id=1
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'user_2' => [
'driver' => 'mysql',
'host' => 'dbhost', // for user with id=2
'database' => 'dbname', // for user with id=2
'username' => 'dbusername', // for user with id=2
'password' => 'dbpassword', // for user with id=2
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
],
],
'migrations' => 'migrations',
'redis' => [ ... ],
];
As you can see, each tenant has its own database instance that can be located on a different host and have a different username/password. Tenanti needs to be told how to figure out which database to use. This is what the documentation on Database Connection Resolver describes. In their example, they've named their tenant databases using acme_{$user->id} whereas in my example above I used user_{$user->id}.
Like I said, I've never actually set this up myself, but these are my best guesses based on the docs, and having used other packages by this same developer. Hope this helps!

Categories