I gotta problem with laravel Auth multi guard technology,
here is my config file
'defaults' => [
'guard' => 'admin',
],
'guards' => [
'admin' => [
'driver' => 'session',
'provider' => 'user',
],
'front' => [
'driver' => 'session',
'provider' => 'front',
],
],
'providers' => [
'admin' => [
'driver' => 'eloquent',
'model' => App\Modules\Admin\Models\User::class,
],
'front' => [
'driver' => 'eloquent',
'model' => App\Modules\WebUser\Models\WebUser::class,
],
],
The problem is that when I try to login by using front guard with id (primary key) like this Auth::guard('front')->loginUsingId(1); it returns me null, when I do like this Auth::loginUsingId(1); it logs me in, the this is that is working only with default guard, when I change defaults it works, but when trying to use a guard to login which is not set as default, then it does nothing. Any ideas why? May be I am missing something or what
According to how laravel works, this
Auth::guard('front')->loginUsingId(1);
will always return null. But trust me the Auth helper is working perfectly here.
To check if the user logged in or not
return Auth::guard('front')->user();
That will make a lot of sense once you see the output above.
Then you execute this:
Auth::guard('front')->loginUsingId(1);
You has been successfully logged in. You can test it with:
Auth::guard('front')->id();
If you try testing
auth()->id();
you will get 'null', because it's checking only default guard
You can try this solution:
Auth::guard('web')->loginUsingId(1);
$user=Auth::user();
$user->created_at=date('Y-m-d H:i:s');
$user->save();
Related
I am using laravel 5.6. I tried to use JWT. That's why I made some modification followed by https://jwt-auth.readthedocs.io/en/develop/quick-start/ . Now jwt is working properly.I checked it by postman. But when I try to use laravel basic login with email and password it does not work. Thanks in advance
I also made change on
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
...
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
is because you are telling laravel to use jwt as driver and the laravel basic login use session as driver, if you want to have both you may need to put this
'web' => [
'driver' => 'session',
'provider' => 'users',
],
and especify the guard that you will use for the login
if (Auth::guard('web')->attempt($credentials)) {
//
}
I use the built-in "Remember me" functionnality of Laravel 5.8. I checked the cookies and saw the remember-me cookie expires in about 5 years. That is way to long and I would like to shorten it. As Laravel automaticly creates the cookie, I don't have the hand on it. How can I do this ?
The remember me duration can be overridden by overriding the AuthenticatesUsers trait. You could add the following code to LoginController that overrides the trait in the following controller:
protected function sendLoginResponse(Request $request)
{
$customRememberMeTimeInMinutes = 10;
$rememberTokenCookieKey = Auth::getRecallerName();
Cookie::queue($rememberTokenCookieKey, Cookie::get($rememberTokenCookieKey), $customRememberMeTimeInMinutes);
$request->session()->regenerate();
$this->clearLoginAttempts($request);
return $this->authenticated($request, $this->guard()->user())
?: redirect()->intended($this->redirectPath());
}
An alternative is to invalidate the remember me session by setting the remember_token in the users table to an empty value.
Example:
$user = Auth::user();
$user->remember_token = null;
$user->save();
This is (at time of writing) so much easier with Laravel 8 (and likely earlier).
Just add the key remember to the appropiate guard in your config/auth.php file. In this example I have a custom guard called customGuard
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'customGuard' => [
'driver' => 'session',
'provider' => 'users',
'remember' => "10080" //Number of minutes the "remember me" option works for.
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
You can set the remember me cookie duration by adding 'remember' => 43800 in the config in config/auth.php
Just change:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
to:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
'remember' => 43800 // Set remember me duration here (minutes)
],
],
Note: The 'remember' key is a mandatory keyword, because it will be read by laravel in Illuminate\Auth\AuthManager namespace
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 have multiple entities in my application that need to be authenticated. So I defined multiple guards to do so:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'customers',
],
'customer' => [
'driver' => 'passport',
'provider' => 'customers',
],
'partner' => [
'driver' => 'passport',
'provider' => 'partners',
],
'admin' => [
'driver' => 'passport',
'provider' => 'admins',
],
],
Then in my Login controllers I have the following condition:
if (Auth::guard('admin')->attempt(['email' => $email, 'password' => $password])) {
...
...
}
when I try to do so (even though it's written in the docs) I get an error telling me that "method attempt does not exist".
So I try defining the guard method on the controller (also like the docs) like this:
protected function guard()
{
return Auth::guard('admin');
}
authentication still doesn't work with the right credentials (I tried to check what guard the Auth facade was using before the attempt using dd(Auth::guard()) and it was the default web guard.
I tried removing the web guard from the default guards array in auth config. didn't work.
I also tried config:clear and rerunning the server but nothing worked!
I am out of ideas. I know that I can write my own simple login, but why reinvent the wheel, and I was following the docs to the letter. help.
I have multi-authentication set up in my laravel app. I set up different guards and providers for admin, doctor and patient. I've also set up the redirects for the various guards in my config\auth.php.
The only issue i'm having right now is, I want doctors to login with a unique number called MDCN which is saved to the database table instead of email. Please how do i customize the login for the doctors?
Ps: I've also set up the models for each, and i use laravel default auth.
my guard:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'admin-api' => [
'driver' => 'token',
'provider' => 'admins',
],
'doctor' => [
'driver' => 'session',
'provider' => 'doctors',
],
'doctor-api' => [
'driver' => 'token',
'provider' => 'doctors',
],
],
and provider:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
'doctors' => [
'driver' => 'eloquent',
'model' => App\Models\Doctor::class,
],
],
In the App\Http\Controllers\Auth\LoginController you can override a method which returns by what fields the authentication should be checked and there you can pass the MDCN if you're logging a doctor:
protected function credentials(Request $request)
{
return $request->only('MDCN', 'password');
}
i finally solved this, thank to Alex Curtis.
In order to do this, you need to customize each model to tell it what you want to use to login.
So on any model that you want to log in with a username instead of an email you need to add this block of code to the model:
public function username()
{
return 'username';
}
And just make sure that the value you return (username in this example) matches the column name in that model's table that has the identifier you are looking to use.
Obviously you would also want to make sure you have a column in the DB to hold this data, you want it to be mass-assignable (by customizing the $fillable array in the model) and you also want the column to be indexed and unique.
To get this you want to create the column in a migration that looks like this:
$table->string('username')->unique();
This will make a unique index for that column.
The default is email, so if you are using email then you don't need to worry about this, but any model using something other than email will need this change made to that user type's model.