I'm currently upgrading a Laravel 5.4 project to Laravel 10, which involves transitioning from PHP 5.6 to PHP 8.3. The project uses tymon/jwt-auth for JWT authentication and zizaco/entrust for role-based authentication. However, I've encountered compatibility issues with zizaco/entrust in the updated Laravel version, affecting the authentication process.
I explained the steps I plan to take during the migration:
- Upgrade Laravel and PHP Versions: Transition to Laravel 10 and PHP 8.3, addressing syntax changes and compatibility issues. JWT Authentication: Continue using tymon/jwt-auth, configuring tokens
- with role_id and role_name. Role-based Authentication: Replace zizaco/entrust due to incompatibility. Considering other solutions or custom implementations involving role_id and role_name in JWT tokens.
- Middleware Updates: Modify middleware to support new role-based authentication system.
Custom Middleware Example:
<?php
namespace App\Http\Middleware;
use Closure;
use Log;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Illuminate\Support\Facades\Response;
use Tymon\JWTAuth\Middleware\BaseMiddleware;
use DB;
class TokenEntrustAbility extends BaseMiddleware
{
public function handle($request, Closure $next, $roles, $permissions, $validateAll = false)
{
if (!$token = $this->auth->setRequest($request)->getToken()) {
return Response::json(array('code' => 201, 'message' => 'Required field token is missing or empty.', 'cause' => '', 'data' => json_decode("{}")));
}
try {
$user = $this->auth->authenticate($token);
//Log::info("Token", ["token :" => $token, "time" => date('H:m:s')]);
if (!$user) {
//Log::error('User not found1.', ['token' => $token,'status_code' =>$user]);
return Response::json(array('code' => 427, 'message' => 'Sorry, We are unable to find you. Please contact the support team.', 'cause' => '', 'data' => json_decode("{}")));
}
// else {
// //if ($user->id != 1) {
// //$is_exist = DB::table('user_session')->where('token', $token)->exists();
// $is_exist = DB::select('SELECT id
// FROM user_session
// WHERE token = ?', [$token]);
// //Log::info('exist session :',['token' => $is_exist]);
//
// if (!$is_exist) {
// //Log::info('session expired data', ['token'=>$token,'id' => $user->id]);
// return Response::json(array('code' => 400, 'message' => 'Your session is expired. Please login.', 'cause' => '', 'data' => json_decode("{}")));
// }
// //}
// }
} catch (TokenInvalidException $e) {
return Response::json(array('code' => 400, 'message' => 'Invalid token.', 'cause' => '', 'data' => json_decode('{}')));
} catch (TokenExpiredException $e) {
try {
$new_token = JWTAuth::refresh($token);
//Log::info("Refreshed Token", ["new_token :" => $new_token, "old_token :" => $token, "time" => date('H:m:s')]);
DB::beginTransaction();
DB::update('UPDATE user_session
SET token = ?
WHERE token = ?', [$new_token, $token]);
DB::commit();
} catch (TokenExpiredException $e) {
//Log::debug('TokenExpiredException Can not be Refresh', ['status_code' => $e->getStatusCode()]);
DB::beginTransaction();
DB::delete('DELETE FROM user_session WHERE token = ?', [$token]);
DB::commit();
return Response::json(array('code' => 400, 'message' => $e->getMessage(), 'cause' => '', 'data' => json_decode('{}')));
} catch (TokenBlacklistedException $e) {
//Log::error('The token has been blacklisted.', ['token' => $token,'status_code' => $e->getStatusCode()]);
DB::beginTransaction();
DB::delete('DELETE FROM user_session WHERE token = ?', [$token]);
DB::commit();
return Response::json(array('code' => 400, 'message' => $e->getMessage(), 'cause' => '', 'data' => json_decode("{}")));
} catch (JWTException $e) {
return Response::json(array('code' => 400, 'message' => $e->getMessage(), 'cause' => '', 'data' => json_decode("{}")));
}
return Response::json(array('code' => 401, 'message' => 'Token expired.', 'cause' => '', 'data' => ['new_token' => $new_token]));
} catch (JWTException $e) {
return Response::json(array('code' => 400, 'message' => $e->getMessage(), 'cause' => '', 'data' => json_decode("{}")));
}
if (!$user) {
//return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404);
//Log::error('User not found.', ['token' => $token,'status_code' =>$user]);
return Response::json(array('code' => 427, 'message' => 'Sorry, We are unable to find you. Please contact the support team.', 'cause' => '', 'data' => json_decode("{}")));
}
if (!$request->user()->ability(explode('|', $roles), explode('|', $permissions), array('validate_all' => $validateAll))) {
return Response::json(array('code' => 201, 'message' => 'Unauthorized user.', 'cause' => '', 'data' => json_decode("{}")));
//return $this->respond('tymon.jwt.invalid', 'token_invalid', 401, 'Unauthorized');
}
$this->events->fire('tymon.jwt.valid', $user);
return $next($request);
}
}
Replace:
if (!$request->user()->ability(explode('|', $roles), explode('|', $permissions), array('validate_all' => $validateAll))) { return Response::json(array('code' => 201, 'message' => 'Unauthorised user.', 'cause' => '', 'data' => json_decode("{}"))); }
With:
if (!in_array($request->user()->role_id, explode('|', $roles))) { return Response::json(array('code' => 201, 'message' => 'Unauthorised user.', 'cause' => '', 'data' => json_decode("{}"))); }
and for my route.php file i a using my middelware like this
Route::group(['prefix' => '', 'middleware' => ['ability:admin|crm,admin_permission|crm_permission']], function () {
//all transaction api
Route::post('getAllTransactionsForAdmin', 'AdminController@getAllTransactionsForAdmin');
Route::post('searchTransaction', 'AdminController@searchTransaction');
Route::post('verifyTransaction', 'AdminController@verifyTransaction');
// //user api
Route::post('getAllUsersByAdmin', 'AdminController@getAllUsersByAdmin');
Route::post('searchUserForAdmin', 'AdminController@searchUserForAdmin');
Route::post('changeUserRole', 'AdminController@changeUserRole');
Route::post('getUserSessionInfo', 'AdminController@getUserSessionInfo');
Route::post('doUserAllSessionLogout', 'LoginController@doUserAllSessionLogout');
//User Design
Route::post('getDesignFolderForAdmin', 'AdminController@getDesignFolderForAdmin');
Route::post('getVideoDesignFolderForAdmin','AdminController@getVideoDesignFolderForAdmin');
Route::post('getIntroDesignFolderForAdmin','AdminController@getIntroDesignFolderForAdmin');
Route::post('getDesignByFolderIdForAdmin', 'AdminController@getDesignByFolderIdForAdmin');
});
here i am creating a group and assign roles and permission that require to access this route.
I'm looking for insights or advice on the migration process, particularly regarding authentication and security. Has anyone faced similar challenges, and how did you address them?