service 4

This commit is contained in:
Hamza-Ayed
2026-05-02 14:50:16 +03:00
parent a6a620f002
commit 40d37cd0d9
2 changed files with 76 additions and 5 deletions

View File

@@ -41,8 +41,16 @@ class JwtService
$this->fpPepper = getenv('FP_PEPPER') ?: '';
$this->issuer = (string)(getenv('APP_ISSUER') ?: '');
$this->redis = $redis;
// Debugging fpPepper
if (empty($this->fpPepper)) {
error_log("[JWT_DEBUG] fpPepper is EMPTY in constructor");
} else {
error_log("[JWT_DEBUG] fpPepper is SET (length: " . strlen($this->fpPepper) . ")");
}
}
// ── توليد Access Token ──────────────────────────────────
public function generateAccessToken(
int|string $userId,
@@ -76,9 +84,28 @@ class JwtService
$payload['fingerPrint'] = hash('sha256', $fingerprint . $this->fpPepper);
}
return JWT::encode($payload, $this->secretKey, self::ALGO);
$token = JWT::encode($payload, $this->secretKey, self::ALGO);
// تخزين في Redis لضمان عدم التكرار وإمكانية الإلغاء
if ($this->redis) {
$this->redis->setex("active_jti:{$userId}", $ttl, $jti);
$this->redis->setex("active_token:{$userId}:{$audience}", $ttl, $token);
}
return $token;
}
// ── فك تشفير التوكن للتحقق الداخلي ────────────────────────
public function decodeToken(string $token): ?object
{
try {
return JWT::decode($token, new Key($this->secretKey, self::ALGO));
} catch (Exception $e) {
return null;
}
}
// ── توليد Refresh Token ─────────────────────────────────
public function generateRefreshToken(int|string $userId): array
{
@@ -176,12 +203,21 @@ class JwtService
if ($this->fpPepper && $tokenType === 'access') {
$fpInToken = $decoded->fingerPrint ?? null;
$fpHeader = $_SERVER['HTTP_X_DEVICE_FP'] ?? null;
// محاولة جلب الهيدر بطرق بديلة إذا لم يوجد في $_SERVER
if ($fpHeader === null && function_exists('getallheaders')) {
$headers = array_change_key_case(getallheaders(), CASE_LOWER);
$fpHeader = $headers['x-device-fp'] ?? null;
}
if ($fpInToken === null || $fpHeader === null) {
error_log("[SECURITY] Fingerprint missing | user: $userId");
$allHeaders = json_encode(getallheaders());
error_log("[SECURITY] Fingerprint missing | user: $userId | fpInToken: " . ($fpInToken ?? 'NULL') . " | fpHeader: " . ($fpHeader ?? 'NULL') . " | Headers: $allHeaders");
self::abort(403, 'Device verification required');
}
$expected = hash('sha256', $fpHeader . $this->fpPepper);
if (!hash_equals($expected, $fpInToken)) {
error_log("[SECURITY] Device mismatch | user: $userId | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '?'));
@@ -232,7 +268,13 @@ class JwtService
}
}
public function getFpPepper(): string
{
return $this->fpPepper;
}
private static function abort(int $code, string $message)
{
error_log("[JWT_AUTH_FAILED] Code: $code | Message: $message | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '?') . " | URI: " . ($_SERVER['REQUEST_URI'] ?? '?'));
http_response_code($code);