Laravel Passport use Different Model - php

I want to add a custom guard to Laravel that uses Passport but with different model (not User), but when I try to set the user for this guard it is not working.
config/auth.php:
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
'conference' => [
'driver' => 'passport',
'provider' => 'participants',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'participants' => [
'driver' => 'eloquent',
'model' => App\Models\Participant::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| Here you may set the options for resetting passwords including the view
| that is your password reset e-mail. You may also set the name of the
| table that maintains all of the reset tokens for your application.
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'email' => 'spark::auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
],
];
in the controller I am setting the user for the custom guard:
auth()->guard('conference')->setUser($participant);
api.php:
Route::group(['prefix' => '{activity}', 'middleware' => ['auth:conference', 'api']], function () { //
Route::group(['prefix' => 'participant/{participant}'], function () {
Route::any('join', 'API\ConferenceController#join');
});
});
Participant model:
use Laravel\Passport\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Participant extends Authenticatable
{
use Enums, SoftDeletes, RequiresUUID, HasApiTokens, Notifiable;
but I can't access the route I get 401. When I change the provider for the 'conference' guard to be 'users' it works without problem.
What I am missing?

This might help:
My AdminAPI Url: https://example.com/api/login
My Customer API Url: https://example.com/api.customer/login
adding this to any ServiceProvider (I have added in RouteServiceProvider.php before custom route)
// Fix/Support for multiple user with different table by changing provider on api.customer circumstances
Config::set('auth.guards.api.provider', request()->input('provider', starts_with(request()->path(), 'api.customer') ? 'customers' : 'users'));`
and must add your custom provider in providers array in config/auth.php
'customers' => [
'driver' => 'eloquent',
'model' => App\Customer::class,
],

If you just only change User model to 'participants' you can replace provider to 'participants' in api. Multi auth I found a temporary solution, idea comes from https://github.com/laravel/passport/issues/161
and http://esbenp.github.io/2017/03/19/modern-rest-api-laravel-part-4/
Laravel\Passport\Brigde\UserRepository.php file add:
public function getEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity, $provider) {
$provider = config('auth.guards.' . $provider . '.provider');
if (is_null($model = config('auth.providers.' . $provider . '.model'))) {
throw new RuntimeException('Unable to determine authentication model from configuration.');
}
if (method_exists($model, 'findForPassport')) {
$user = (new $model)->findForPassport($username);
} else {
$user = (new $model)->where('email', $username)->first();
}
if (!$user) {
return;
} elseif (method_exists($user, 'validateForPassportPasswordGrant')) {
if (!$user->validateForPassportPasswordGrant($password)) {
return;
}
} elseif (!$this->hasher->check($password, $user->getAuthPassword())) {
return;
}
return new User($user->getAuthIdentifier());
}
League\OAuth2\Server\Grant\PasswordGrant.php 78 line add
$provider = $this->getRequestParameter('provider', $request);
and 94 line add $provider, like:
$user = $this->userRepository->getEntityByUserCredentials(
$username,
$password,
$this->getIdentifier(),
$client,
$provider
);
Write LoginProxy(in fact it should be receive different Model in constructor ) like:
class LoginProxy {
const REFRESH_TOKEN = 'refreshToken';
private $client;
private $user;
public function __construct(User $user, Client $client) {
$this->user = $user;
$this->client = $client;
}
public function attemptLogin($mobile, $password) {
$user = $this->user->where('mobile', $mobile)->first();
if (!is_null($user)) {
return $this->proxy('password', [
'username' => $mobile,
'password' => $password,
]);
}
return response()->json('error for 401', 401);
}
public function attemptRefresh() {
$refreshToken = $this->request->cookie(self::REFRESH_TOKEN);
return $this->proxy('refresh_token', [
'refresh_token' => $refreshToken,
]);
}
public function proxy($grant_type, array $data = []) {
$data = array_merge($data, [
'client_id' => env('PASSWORD_CLIENT_ID'),
'client_secret' => env('PASSWORD_CLIENT_SECRET'),
'grant_type' => $grant_type,
'scope' => '*',
]);
$response = $this->client->post(url('/oauth/token'), [
'form_params' => $data,
]);
$data = json_decode($response->getBody()->getContents());
return response()->json([
'token_type' => $data->token_type,
'access_token' => $data->access_token,
'refresh_token' => $data->refresh_token,
'expires_in' => $data->expires_in,
], 200);
}
public function logout() {
$accessToken = $this->auth->user()->token();
$refreshToken = $this->db
->table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update([
'revoked' => true,
]);
$accessToken->revoke();
}
}
in your LoginController, call certain method:
class LoginController extends Controller {
private $loginProxy;
public function __construct(LoginProxy $loginProxy) {
$this->loginProxy = $loginProxy;
}
public function login(LoginRequest $request) {
$mobile = $request->get('mobile');
$password = $request->get('password');
$provider = $request->get('provider');
return $this->loginProxy->attemptLogin($mobile, $password, $provider);
}
public function refresh(Request $request) {
return $this->response($this->loginProxy->attemptRefresh());
}
public function logout() {
$this->loginProxy->logout();
return $this->response(null, 204);
}
Now you can post different provider params to it.

Related

Laravel 8 Custom Login With Custom Model

Greetings to all I have a problem with my Laravel 8 code I'm getting
"ErrorException Undefined index: password" from vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php:159
I use custom model and I set up in config/auth.php to use my Client model not a User model and when I try Auth::attempt($credentials) it's failed and give me that error here is my code
Client.php Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Client extends Authenticatable
{
use HasFactory;
protected $table = 'clients';
protected $primaryKey = 'client_id';
public $incrementing = true;
protected $fillable = ['client_firstName', 'client_lastName', 'client_email', 'client_phoneNumber', 'client_password', 'client_isAdmin', 'client_created_at', 'client_updated_at'];
public $timestamps = true;
const CREATED_AT = 'client_created_at';
const UPDATED_AT = 'client_updated_at';
}
config/auth.php
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\Client::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
ClientController.php
public function signIn(Request $request){
if($request->isMethod('POST')){
$validator = Validator::make($request->all(), [
'signin_email' => 'required|string|email:rfc,dns|bail',
'signin_password' => 'required|string|bail',
], [
'signin_email.required' => 'The email address field is required.',
'signin_email.email' => 'You must provide an a valid email address.',
'signin_password.required' => 'The password field is required.',
]);
if($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}else{
$credentials = [
'client_email' => $request->signin_email,
'client_password' => $request->signin_password,
];
if(Auth::attempt($credentials)) {
return redirect()->to('dashboard');
}else{
return redirect()->back()->withErrors("Sorry, the passed email address or password is incorrect, try again!")->withInput();
}
}
}else{
return view('signIn');
}
}
I have found a solution I will need to add to my model getAuthPassword, also I need to change app/auth.php and ClientController.php
Client.php Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Client extends Authenticatable
{
use HasFactory;
protected $table = 'clients';
protected $primaryKey = 'client_id';
public $incrementing = true;
protected $fillable = ['client_firstName', 'client_lastName', 'client_email', 'client_phoneNumber', 'client_password', 'client_isAdmin', 'client_created_at', 'client_updated_at'];
public $timestamps = true;
const CREATED_AT = 'client_created_at';
const UPDATED_AT = 'client_updated_at';
public function getAuthPassword(){
return $this->client_password;
}
}
app/auth.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'clients',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'clients',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'clients' => [
'driver' => 'eloquent',
'model' => App\Models\Client::class,
'table' => 'clients',
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'clients' => [
'provider' => 'clients',
'table' => 'clients',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
ClientController.php
public function signIn(Request $request){
if($request->isMethod('POST')){
$validator = Validator::make($request->all(), [
'signin_email' => 'required|string|email:rfc,dns|bail',
'signin_password' => 'required|string|bail',
], [
'signin_email.required' => 'The email address field is required.',
'signin_email.email' => 'You must provide an a valid email address.',
'signin_password.required' => 'The password field is required.',
]);
if($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}else{
$credentials = [
'client_email' => $request->signin_email,
'password' => $request->signin_password,
];
if(Auth::attempt($credentials)) {
return redirect()->to('dashboard');
}else{
return redirect()->back()->withErrors("Sorry, the passed email address or password is incorrect, try again!")->withInput();
}
}
}else{
return view('signIn');
}
}

Call to undefined method App\Models\User::createToken()

I'm new to Laravel and i'm getting this error: Call to undefined method App\Models\User::createToken()
Laravel Framework 8.34.0
PHP 7.4.3
My Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
class UserController extends Controller
{
private $sucess_status = 200;
public function createUser(Request $request){
$validator = Validator::make($request->all(),
[
'first_name' => 'required',
'last_name' => 'required',
'phone' => 'required|numeric',
'email' => 'required|email',
'password' => 'required|alpha_num|min:5'
]
);
if($validator->fails()){
return response()->json(["validattion_errors"=>$validator->errors()]);
}
$dataArray = array(
"first_name"=>$request->first_name,
"last_name"=>$request->last_name,
"full_name"=>$request->first_name . " " . $request->last_name,
"phone"=>$request->phone,
"email"=>$request->email,
"password"=>bcrypt($request->password),
);
$user = User::create($dataArray);
if(!is_null($user)){
return response()->json(["status" => $this->sucess_status, "success" => true, "data" => $user]);
}else {
return response()->json(["status" => "failed", "success" => false, "message" => "User not created"]);
}
}
public function userLogin(Request $request){
$validator = Validator::make($request->all(),
[
'email' => 'required|email',
'password' => 'required|alpha_num|min:5'
]
);
if($validator->fails()){
return response()->json(["validation_errors"=>$validator->errors()]);
}
if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){
$user = Auth::user();
$token = $user->createToken('token')->accessToken;
return response()->json(["status" => $this->sucess_status, "success" => true, "login" => true, "token" => $token, "data" => $user]);
} else{
return response()->json(["status" => "failed", "success" => false, "message" => "Invalid email or password"]);
}
}
public function userDetail(){
$user = Auth::user();
if(!is_null($user)){
return response()->json(["status" => $this->sucess_status, "success" => true, "user" => $user]);
}else {
return response()->json(["status" => "failed", "success" => false, "message" => "No user found"]);
}
}
}
My Auth.php:
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
I had run the php artisan passport: install command 3 times
because I forgot to save the file with the settings and I thought it would be necessary to run the code again after saving the file
And returned me this:
Encryption keys already exist. Use the --force option to overwrite them.
Personal access client created successfully.
Client ID: 3
Client secret: JoZbAGCSOZ6t0hn7YnnT6PdN4EMUUZa7H1vU6Sk2
Password grant client created successfully.
Client ID: 4
Client secret: yAxjrBnvPWCiAdXod5FmJDQTNDmneRoO1LtM6B0x
cristiansto in Laravel/API/todoList
❯ php artisan passport:install --force
Encryption keys generated successfully.
Personal access client created successfully.
Client ID: 5
Client secret: 8CtWyvXIwapZnfO5dTGDsyF0iXvJsxNyiZeUksTL
Password grant client created successfully.
Client ID: 6
Client secret: 9jThPxOfgNxJINFKIbDz0WU5yYEup0pIkboEJLr0
cristiansto in Laravel/API/todoList
I dont know if this is the cause.
What could it be?
the method createToken is in HasApiTokens trait, you should use it In your User Model
:
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens;
}
I discovered the issue, i had to put
use Laravel\Passport\HasApiTokens; inside the User.php
and then
use HasFactory, Notifiable, HasApiTokens;
It works on me
Laravel Framework 8.83.5
PHP 7.4.19
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
....
}
HasFactory and Notifiable are default User Model, just add HasApiTokens so it becomes:
use HasApiTokens, HasFactory, Notifiable;

Why Auth::user(); gives different data from loged-in user? Laravel

I try to make login using Auth, its work seems fine but when I check the stored/logged-in data user is different.
here's the code in authController
public function auth(Request $request)
{
$rules = [
'username' => 'required|string',
'password' => 'required|string'
];
$msg = [
'username.required' => 'wajib isi username',
'username.string' => 'not username',
'password.required' => 'wajib isi password',
'password.string' => 'string password',
];
$validator = Validator::make($request->all(), $rules, $msg);
if($validator->fails()){
return redirect()->back()->withErrors($validator)->withInput($request->all());
}
$data = [
'userid' => $request['username'],
'password' => $request['password']
];
Auth::attempt($data);
if(Auth::check()){
dd(Auth::user());
return redirect('dashboard');
}else{
Session::flash('error', 'ada yang salah ops!');
// return redirect('login');
}
}
when I 'dd(Auth::user());' after Auth::check() the data is correct, example
Then I check it on the dashboard page with the following code in adminController
public function dashboard()
{
dd(Auth::user());
return view('admin/masterdata/blank');
}
It's given me this result
and here's my User model look like
class User extends Authenticatable
{
protected $table = 'tbl_user';
protected $primaryKey = 'userid';
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'nama', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
UPDATE
and here is my config/auth.php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
Is the words users in config/auth.php mean the users model?
Is something wrong with my code or something I miss?
Thanks in advance.
try this other way as you have userid and password to check for login
use Illuminate\Support\Facades\Hash;
public function auth(Request $request)
{
$rules = [
'username' => 'required|string',
'password' => 'required|string'
];
$msg = [
'username.required' => 'wajib isi username',
'username.string' => 'not username',
'password.required' => 'wajib isi password',
'password.string' => 'string password',
];
$validator = Validator::make($request->all(), $rules, $msg);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput($request->all());
}
$user = User::where('userid', $request['username'])->first();
if (!$user) {
return redirect()->with('error', 'user not found.');
}
if (Hash::check($request['password'],$user->password);) {
auth()->login($user);
return redirect('dashboard');
} else {
Session::flash('error', 'ada yang salah ops!');
}
}
then try in adminController.php
public function dashboard()
{
dd(Auth::user());
return view('admin/masterdata/blank');
}
here i used auth()->login($user); to login valid user

Laravel using 2 api levels at the same time apart from each other

I am trying to create an API application using laravel.
I want to use the system with 2 levels: normal api and customers api.
This means that the standard api routes are being authenticated by the normal guard (users) with the user model and the customers api route are being authenticated by a different guard (customers) with the customer model.
Now the problem is whenever I login into the customers api and retrieve a token, that token can be used to access the normal api as well which I don't want.
I created a middleware to log the auth user and it shows both models but only the customer one should be logged in to.
Scenario as follows: I log into customers login route and then try to access routes from both the normal and customers api and it logs the model for the route but the models are different and the default user one shouldn't be accessed.
Whenever I go to: /api/v1/user-role/all (normal api)
(I removed private data from the logs)
[2020-11-11 11:30:28] local.INFO: req [{"Illuminate\\Http\\Request":"GET /api/v1/user-role/all }]
[2020-11-11 11:30:28] local.INFO: user [{"App\\Models\\User":{"id":1}]
When I go to: /api/v1/customer/customer/paginate (customers side)
[2020-11-11 11:30:28] local.INFO: req [{"Illuminate\\Http\\Request":"GET /api/v1/customer/customer/paginate?establishment_id=332}]
[2020-11-11 11:30:28] local.INFO: user [{"App\\Models\\Customer":{"id":1}}]
User model:
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
use SoftDeletes { restore as private restoreSoftDeletes; }
use EntrustUserTrait { restore as private restoreEntrustUserTrait; }
protected $guard = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'username', 'email', 'password','active', 'firstname', 'lastname',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that are dates.
*
* #var array
*/
protected $dates = [
'created_at', 'updated_at', 'deleted_at',
];
/**
* Automatically creates hash for the user password.
*
* #param string $value
* #return void
*/
public function setPasswordAttribute($value)
{
$this->attributes['password'] = Hash::make($value);
}
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* #return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [];
}
public function restore()
{
$this->restoreSoftDeletes();
$this->restoreEntrustUserTrait();
}
public function roles()
{
return $this->belongsToMany('App\Models\User\Role', 'role_user');
}
public function ServiceRequests()
{
return $this->hasMany('App\Models\ServiceRequest');
}
public function followUpRequests()
{
return $this->hasMany('App\Models\ServiceRequest', 'requested_by');
}
public function isAdmin()
{
return $this->roles()->where('name', 'admin')->exists();
}
}
Customer model:
class Customer extends Authenticatable implements JWTSubject
{
use Notifiable;
use SoftDeletes { restore as private restoreSoftDeletes; }
use EntrustUserTrait { restore as private restoreEntrustUserTrait; }
protected $guard = 'customers';
protected $fillable = ['email', 'password','active', 'firstname', 'lastname'];
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $hidden = ['password', 'remember_token'];
public function establishment(){
return $this->belongsTo(Establishment::class);
}
public function company()
{
return $this->belongsTo('App\Models\Company');
}
public function roles()
{
return $this->belongsToMany(Role::class, 'customers_roles');
}
public function setPasswordAttribute($value)
{
$this->attributes['password'] = Hash::make($value);
}
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
public function restore()
{
$this->restoreSoftDeletes();
$this->restoreEntrustUserTrait();
}
public function isAdmin()
{
return $this->roles()->where('name', 'admin')->exists();
}
}
config/auth.php:
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
'customers' => [
'driver' => 'jwt',
'provider' => 'customers',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'customers' => [
'driver' => 'eloquent',
'model' => App\Models\Customer::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
'customers' => [
'provider' => 'customers',
'table' => 'password_resets',
'expire' => 60,
],
],
];
routes/api.php
$api = app(Router::class);
$api->version('v1', function (Router $api) {
$api->group(['prefix' => 'v1'], function(Router $api) {
$api->group(['prefix' => 'auth'], function(Router $api) {
$api->post('signup', 'App\\Api\\V1\\Controllers\\Auth\\SignUpController#signUp');
$api->post('login', 'App\\Api\\V1\\Controllers\\Auth\\LoginController#login');
$api->post('forgot-password', 'App\\Api\\V1\\Controllers\\Auth\\ForgotPasswordController#sendResetEmail');
$api->post('recovery', 'App\\Api\\V1\\Controllers\\Auth\\ForgotPasswordController#sendResetEmail');
$api->post('reset', 'App\\Api\\V1\\Controllers\\Auth\\ResetPasswordController#resetPassword');
$api->post('logout', 'App\\Api\\V1\\Controllers\\Auth\\LogoutController#logout');
$api->post('refresh', 'App\\Api\\V1\\Controllers\\Auth\\RefreshController#refresh');
});
$api->group(['middleware' => 'jwt.auth'], function(Router $api) {
//routes
});
});
routes/customers-api.php
$api = app(Router::class);
$api->version('v1', function (Router $api) {
$api->group(['prefix' => 'v1'], function(Router $api) {
$api->group(['prefix' => 'customer'], function(Router $api) {
$api->group(['prefix' => 'auth'], function (Router $api) {
$api->post('signup', 'App\\Api\\V1\\Controllers\\Auth\\SignUpController#signUp');
$api->post('login', 'App\\Api\\V1\\Customer\\Controllers\\Auth\\LoginController#login');
$api->post('forgot-password', 'App\\Api\\V1\\Customer\\Controllers\\Auth\\ForgotPasswordController#sendResetEmail');
$api->post('recovery', 'App\\Api\\V1\\Customer\\Controllers\\Auth\\ForgotPasswordController#sendResetEmail');
$api->post('reset', 'App\\Api\\V1\\Controllers\\Auth\\ResetPasswordController#resetPassword');
$api->post('logout', 'App\\Api\\V1\\Controllers\\Auth\\LogoutController#logout');
$api->post('refresh', 'App\\Api\\V1\\Controllers\\Auth\\RefreshController#refresh');
});
$api->group(['middleware' => ['assign.guard:customers','jwt.auth']], function (Router $api) {
//routes
});
});
});
});
customers/LoginController.php
public function login(LoginRequest $request, JWTAuth $JWTAuth)
{
$customer = Customer::with(['roles'])->where('email', $request->email)->where('active', 1)->first();
if ($customer) {
if (Hash::check($request->password, $customer->password)) {
// $credentials = $request->only('email', 'password');
try {
$token = Auth()->guard('customers')->attempt(['email' => $request->email, 'password' => $request->password]);
if (!$token) {
return response()->json([
'title' => \Lang::get('app.error'),
'message' => \Lang::get('auth.accessDenied')
], 403);
} else {
return response()->json([
'return_value' => true,
'title' => \Lang::get('app.success'),
'message' => \Lang::get('auth.loginSuccessful'),
'token' => $token
'user' => $customer,
'isAdmin' => $customer->isAdmin()
], 200);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
} else {
return response()->json([
'return_value' => false,
'title' => \Lang::get('app.error'),
'message' => \Lang::get('auth.accessDenied')
], 403);
}
} else {
return response()->json([
'return_value' => false,
'title' => \Lang::get('app.error'),
'message' => \Lang::get('auth.accessDenied')
], 403);
}
}
I think the problem is since you probably are using the jwt-auth package, you need to specifically point out which configuration you should use in each login controller.
customers/LoginController.php
function __construct()
{
Config::set('jwt.user', Customer::class);
Config::set('auth.providers', [
'users' => [
'driver' => 'eloquent',
'model' => Customer::class
]
]);
}

Symfony\Component\Debug\Exception\FatalThrowableError: Argument 2 passed to Illuminate\Auth\SessionGuard::__construct()

I'm trying to implement Laravel passport for two tables, so one would be default User and second one would be for Devices.
I created in the config the Guard for the new model and if I try to register the devices its writing to the Device table everything but, right now if I try to login it gives me this error:
Symfony\Component\Debug\Exception\FatalThrowableError: Argument 2 passed to Illuminate\Auth\SessionGuard::__construct() must implement interface Illuminate\Contracts\Auth\UserProvider, null given, called in /Users/petarceho/laravel/api/vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php on line 127 in file /Users/petarceho/laravel/api/vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php on line 99
I'm new to Laravel so sorry for not able to explain it well, but can I use Laravel passport for two tables.
Here is my Controller class for Devices :
<?php
namespace App\Http\Controllers;
use App\Device;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class DeviceController extends Controller{
//register
public function signupDevice(Request $request)
{
//cant registed with the same email twice
if(sizeof(Device::where('name','=',$request->query('name'))->get()) > 0)
return response()->json(['name has already been taken'],500);
$request->validate([
'name' => 'required|string',
'password' => 'required|string|confirmed']);
$device =new Device(
[
'name'=>$request->name,
'password'=>bcrypt($request->password)
]);
$device->save();
return response()->json([
'message' => 'Successfully created device!'
], 201);
}
public function login(Request $request)
{
if (Auth::guard('device')->attempt(['name' => request(['name']), 'password' => request(['password'])])) {
$details = Auth::guard('device')->user();
$user = $details['original'];
return $user;}
else {return 'auth fail';}
}
public function login1(Request $request){
//validate the data input
$request->validate([
'name' => 'required|string', // |string|name
'password' => 'required|string',
// 'remember_me' => 'boolean'
]);
$credentials = request(['name', 'password']);
if(!Auth::attempt($credentials))
return response()->json([
'message' => 'Unauthorized'
], 401);
$device = $request->user('device');
// $device = Auth::guard('device')->device();
$tokenResult = $device->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me)
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
],200);
}
}
Here is my config auth.php file.
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
'device'=>
[
'driver'=>'session',
// 'model'=>App\Device::class,
'provider'=>'devices',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'devices' => [
'driver' => 'eloquent',
'model' => App\Device::class,
],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
];
and my routes:
//routes for device auth
Route::group(
[
'prefix'=>'auth/device'
],function ()
{
Route::post('signup','DeviceController#signupDevice');
Route::post('login','DeviceController#login');
});
the App/Device class
the Illuminate\Foundation\Auth\Device looks exactly like User class
<?php
namespace App;
use Illuminate\Foundation\Auth\Device as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class Device extends Authenticatable{
use Notifiable;//,HasApiTokens;
protected $table ='device';
protected $fillable = [
'name', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
Any idea how to use Laravel passport for Multi auth authentication for two tables ?

Categories