fix: Isolate OTP keys and sessions per role in Redis so teacher and student logins on the same phone number never collide

This commit is contained in:
Hamza-Ayed
2026-08-29 05:29:26 +03:00
parent a8700c656f
commit 9fc60b2cf5
+8 -4
View File
@@ -77,11 +77,13 @@ class AuthController
// 2. Generate 6-digit OTP
$otp = (string)random_int(100000, 999999);
// 3. Save OTP in Redis (TTL: 300s / 5 minutes)
// 3. Save OTP in Redis (TTL: 300s / 5 minutes) - Role-isolated to prevent Teacher/Student collision
try {
$redis = RedisClient::getInstance();
$otpKey = "otp:{$phoneHash}";
$otpKey = "otp:{$phoneHash}:{$role}";
$redis->setex($otpKey, 300, password_hash($otp, PASSWORD_BCRYPT));
// Also store general key for backwards compatibility
$redis->setex("otp:{$phoneHash}", 300, password_hash($otp, PASSWORD_BCRYPT));
} catch (\Exception $e) {
error_log("Redis OTP store error: " . $e->getMessage());
}
@@ -162,14 +164,16 @@ class AuthController
$phoneHash = Security::blindIndex($cleanPhone);
// 1. Verify OTP against Redis
// 1. Verify OTP against Redis (Check role-isolated key first, then fallback)
$redis = RedisClient::getInstance();
$otpRoleKey = "otp:{$phoneHash}:{$role}";
$otpKey = "otp:{$phoneHash}";
$storedHash = $redis->get($otpKey);
$storedHash = $redis->get($otpRoleKey) ?: $redis->get($otpKey);
$isValidOtp = false;
if ($storedHash && password_verify($inputOtp, $storedHash)) {
$isValidOtp = true;
$redis->del($otpRoleKey);
$redis->del($otpKey); // Invalidate OTP after success
}