CodeIgniter无法捕获JWT过期异常,跳转登录页失败
问题:CodeIgniter中JWT过期异常无法捕获,无法跳转登录页
我需要每次刷新页面时校验JWT Token,将其作为过滤器使用。Token不存在或被清除时能正常跳转至登录页,但Token过期时,CodeIgniter会直接抛出JWT过期异常,无法捕获异常并携带Flash数据跳转登录页。
尝试在调用校验函数时嵌套try-catch块,不仅没捕获到错误,反而出现Undefined property: CodeIgniter\HTTP\RedirectResponse::$email错误。
相关代码
jwt_helper.php
function validateJWT($token) { $session = \Config\Services::session(); $model = new UserModel(); $key = getenv('JWT_SECRET_KEY'); try { $decoded_token = JWT::decode($token, new Key($key, 'HS256')); return $decoded_token; } catch (Exception $e) { setcookie('COOKIE-SESSION', null); $session->setFlashdata('message', '<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-300 dark:bg-gray-800 dark:text-red-400" role="alert"> <span class="font-medium">Token Invalid</span>, Please login again </div>'); // echo $e->getMessage(); return redirect()->to('/auth'); } }
DashboardController.php
public function show() { $session = \Config\Services::session(); $token = $_COOKIE['COOKIE-SESSION']; $model = new UserModel(); helper('jwt'); try { $decoded_token = validateJWT($token); $result = $model->show($decoded_token->email); } catch (Exception $e) { $session->setFlashdata('message', '<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-300 dark:bg-gray-800 dark:text-red-400" role="alert"> <span class="font-medium">Session Expired</span>, Please login again </div>'); return redirect()->to('/auth'); } if (!$result) { $data['title'] = 'Login'; $session->setFlashdata('message', 'Session expired, Please login again'); return view('login', $data); } else { $data = [ 'title' => 'Dashboard', 'email' => $result['email'], 'name' => $result['name'], 'image' => $result['image'], 'date_created' => $result['date_created'] ]; $session->set('title', $data['title']); return view('dashboard', $data); } }
UserModel.php
public function show($email) { $session = \Config\Services::session(); $model = new UserModel(); $builder = $this->table('users'); $data = $builder->where('email', $email)->first(); if (!$data) { return false; } else { $data2 = [ 'email' => $data['email'], 'name' => $data['name'], 'image' => $data['image'], 'date_created' => $data['date_created'] ]; return $data2; } }
解决方案
1. 捕获JWT具体异常类
JWT库抛出的不是通用Exception,而是专属异常(如ExpiredException、SignatureInvalidException),需针对性捕获:
修改jwt_helper.php:
use Firebase\JWT\ExpiredException; use Firebase\JWT\SignatureInvalidException; use Firebase\JWT\BeforeValidException; use Exception; function validateJWT($token) { $session = \Config\Services::session(); $key = getenv('JWT_SECRET_KEY'); try { $decoded_token = JWT::decode($token, new Key($key, 'HS256')); return $decoded_token; } catch (ExpiredException $e) { // 正确清除Cookie(设置过期时间为过去) setcookie('COOKIE-SESSION', null, -1, '/'); $session->setFlashdata('message', '<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-300 dark:bg-gray-800 dark:text-red-400" role="alert"> <span class="font-medium">Session Expired</span>, Please login again </div>'); return redirect()->to('/auth'); } catch (SignatureInvalidException|BeforeValidException|Exception $e) { setcookie('COOKIE-SESSION', null, -1, '/'); $session->setFlashdata('message', '<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-300 dark:bg-gray-800 dark:text-red-400" role="alert"> <span class="font-medium">Token Invalid</span>, Please login again </div>'); return redirect()->to('/auth'); } }
2. 处理Helper返回的跳转响应
当Helper返回RedirectResponse时,控制器不能将其当作解码后的Token使用,需先判断类型:
修改DashboardController.php:
public function show() { $session = \Config\Services::session(); // 先检查Cookie是否存在,避免Undefined index错误 if (!isset($_COOKIE['COOKIE-SESSION'])) { $session->setFlashdata('message', '<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-300 dark:bg-gray-800 dark:text-red-400" role="alert"> <span class="font-medium">Session Expired</span>, Please login again </div>'); return redirect()->to('/auth'); } $token = $_COOKIE['COOKIE-SESSION']; $model = new UserModel(); helper('jwt'); $decoded_token = validateJWT($token); // 判断是否为跳转响应,是则直接返回 if ($decoded_token instanceof \CodeIgniter\HTTP\RedirectResponse) { return $decoded_token; } $result = $model->show($decoded_token->email); if (!$result) { $data['title'] = 'Login'; $session->setFlashdata('message', 'Session expired, Please login again'); return view('login', $data); } else { $data = [ 'title' => 'Dashboard', 'email' => $result['email'], 'name' => $result['name'], 'image' => $result['image'], 'date_created' => $result['date_created'] ]; $session->set('title', $data['title']); return view('dashboard', $data); } }
3. 修复UserModel冗余代码
UserModel内无需重新实例化自身,直接使用$this即可:
public function show($email) { $builder = $this->table('users'); $data = $builder->where('email', $email)->first(); if (!$data) { return false; } else { return [ 'email' => $data['email'], 'name' => $data['name'], 'image' => $data['image'], 'date_created' => $data['date_created'] ]; } }
4. 可选:使用框架内置Cookie服务
替代原生setcookie,更符合CodeIgniter规范:
$response = \Config\Services::response(); $response->deleteCookie('COOKIE-SESSION');
内容的提问来源于stack exchange,提问作者cherno304
相关产品推荐
相关产品推荐

