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);
}
}