Add Redis-based permission caching for users and subusers
- Introduced Redis-backed caching for user and subuser permission evaluations in the `route_t` trait, reducing database queries. - Enhanced `Redis` class with methods for permission caching: `cache_permission`, `get_permission`, and `clear_permission`. - Added test coverage for the new caching logic in `PermissionRedisCacheTest.php`. - Implemented Redis caching for authentication sessions with `cache_auth_session`, `get_auth_session`, and `clear_auth_session`. - Improved CORS handling for preflight requests in `index.php`.
This commit is contained in:
@@ -46,8 +46,21 @@ class authRoute
|
||||
if (!isset($data['password']) || empty($data['password']) || strlen($data['password']) < 1) {
|
||||
$response->error('Password is required', 400);
|
||||
}
|
||||
// Try to log the user in
|
||||
$isCredentialsValid = (new authentication())->authenticate($data['customer_number'], $data['password']);
|
||||
|
||||
// Use Redis-backed user and property caches to validate credentials with a single user load
|
||||
$user = (new users_o())->getUserByCustomerNumber($data['customer_number']);
|
||||
if (!$user->exists() || !$user->hasPassword()) {
|
||||
(new logs_o())->add('auth', 'global', 1, 0, 'AUTH_FAILURE', 'Customer number: ' . $data['customer_number']);
|
||||
$response->error('Invalid credentials', 401);
|
||||
}
|
||||
|
||||
$isCredentialsValid = false;
|
||||
try {
|
||||
$isCredentialsValid = $user->passwordMatches($data['password']);
|
||||
} catch (Exception $e) {
|
||||
$isCredentialsValid = false;
|
||||
}
|
||||
|
||||
// Log the incident
|
||||
if ($isCredentialsValid) {
|
||||
(new logs_o())->add('auth', 'global', 1, 0, 'AUTH_SUCCESS', 'Customer number: ' . $data['customer_number']);
|
||||
@@ -55,14 +68,15 @@ class authRoute
|
||||
(new logs_o())->add('auth', 'global', 1, 0, 'AUTH_FAILURE', 'Customer number: ' . $data['customer_number']);
|
||||
$response->error('Invalid credentials', 401);
|
||||
}
|
||||
// If the credentials are valid, create a token
|
||||
$user = (new users_o())->getUserByCustomerNumber($data['customer_number']);
|
||||
|
||||
// If the credentials are valid, check 2FA and create a token
|
||||
if ($user->exists() && $user->isTwoFactorEnabled()) {
|
||||
$token = (new authentication())->create_2fa_token($user->id, '2FA_VERIFICATION_USER');
|
||||
$response->success(['2fa_required' => true, '2fa_token' => $token]);
|
||||
}
|
||||
|
||||
$token = (new authentication())->create_token($data['customer_number']);
|
||||
// Create the auth token without reloading the user from DB
|
||||
$token = (new authentication())->create_token_by_user_id((int)$user->id);
|
||||
// Return the token
|
||||
$response->success(['token' => $token]);
|
||||
});
|
||||
@@ -79,6 +93,8 @@ class authRoute
|
||||
}
|
||||
// Delete the token
|
||||
(new tokens_o())->delete($token);
|
||||
// Clear any cached session for this token
|
||||
try { redis->clear_auth_session($token); } catch (\Throwable $e) {}
|
||||
// Return a success message
|
||||
$response->success(['message' => 'Logged out']);
|
||||
});
|
||||
@@ -93,6 +109,17 @@ class authRoute
|
||||
if (!(new authentication())->validate_token($token)) {
|
||||
$response->error('Invalid token', 401);
|
||||
}
|
||||
|
||||
// Try Redis cache first for session payload
|
||||
try {
|
||||
$cached = redis->get_auth_session($token);
|
||||
if (is_array($cached)) {
|
||||
$response->success($cached);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Ignore Redis errors and continue to compute session
|
||||
}
|
||||
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the user exists
|
||||
@@ -103,6 +130,13 @@ class authRoute
|
||||
$user_data = $user->includeIncludes(['economicCustomer', 'permissions'])->asArray();
|
||||
$user_data['two_factor_enabled'] = $user->isTwoFactorEnabled();
|
||||
|
||||
// Cache the session payload briefly to reduce DB load on hot paths
|
||||
try {
|
||||
redis->cache_auth_session($token, $user_data, 60);
|
||||
} catch (\Throwable $e) {
|
||||
// Best-effort caching only
|
||||
}
|
||||
|
||||
// Return the (session) user object
|
||||
$response->success($user_data);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user