رموز JWT في Kotlin: دليل شامل مع مكتبة jjwt
\n\nفي تطوير الويب الحديث، أصبحت JWT (JSON Web Tokens) معيارًا للمصادقة وتبادل المعلومات بين العميل والخادم. في نظام Kotlin البيئي، خاصة عند إنشاء تطبيقات الخلفية على Spring Boot أو Ktor، غالبًا ما تنشأ الحاجة للعمل مع JWT. في هذه المقالة، سنشرح مكتبة io.jsonwebtoken (jjwt) — الأداة الأكثر شيوعًا للعمل مع JWT في Java/Kotlin.
ما هو JWT؟
\nJWT هي طريقة مضغوطة وآمنة لعناوين URL لتمثيل الادعاءات (claims) بين طرفين. يتكون الرمز من ثلاثة أجزاء مفصولة بنقاط:
\n- \n
- Header — الرأس، يحتوي على نوع الرمز وخوارزمية التوقيع (مثل HS256, RS256). \n
- Payload — الحمولة مع الادعاءات (claims):
sub(الموضوع)،iat(وقت الإصدار)،exp(وقت الانتهاء) وبيانات مخصصة. \n - Signature — التوقيع، الذي يتم إنشاؤه باستخدام مفتاح سري أو زوج مفاتيح. \n
ربط المكتبة
\nللعمل مع JWT في Kotlin، سنستخدم jjwt (io.jsonwebtoken). أضف التبعية في build.gradle.kts:
dependencies {\n implementation("io.jsonwebtoken:jjwt-api:0.12.6")\n runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6")\n runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6") // لتحليل JSON\n}\n\nتوليد رمز JWT
\nلإنشاء رمز، يجب تعيين مفتاح سري، وتحديد الادعاءات، وتوقيع الرمز. مثال بلغة Kotlin:
\nimport io.jsonwebtoken.Jwts\nimport io.jsonwebtoken.security.Keys\nimport java.util.Date\nimport javax.crypto.SecretKey\n\nfun generateToken(userId: String, secret: String): String {\n val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())\n \n val now = Date()\n val expiration = Date(now.time + 3600_000) // +1 ساعة\n \n return Jwts.builder()\n .subject(userId)\n .issuedAt(now)\n .expiration(expiration)\n .claim("role", "USER")\n .signWith(key)\n .compact()\n}\n\nالتحقق من JWT وتحليله
\nعند استلام رمز من العميل، يجب التحقق من توقيعه وصلاحيته. استخدم Jwts.parser():
import io.jsonwebtoken.JwtException\nimport io.jsonwebtoken.Jwts\nimport io.jsonwebtoken.security.Keys\nimport javax.crypto.SecretKey\n\nfun validateToken(token: String, secret: String): Boolean {\n return try {\n val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())\n Jwts.parser()\n .verifyWith(key)\n .build()\n .parseSignedClaims(token)\n true\n } catch (e: JwtException) {\n false\n }\n}\n\nfun extractUserId(token: String, secret: String): String? {\n return try {\n val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())\n val claims = Jwts.parser()\n .verifyWith(key)\n .build()\n .parseSignedClaims(token)\n .payload\n claims.subject\n } catch (e: Exception) {\n null\n }\n}\n\nالعمل مع الادعاءات المخصصة
\nيمكنك إضافة أي بيانات مخصصة إلى الحمولة. على سبيل المثال، تخزين البريد الإلكتروني أو دور المستخدم:
\nfun generateTokenWithCustomClaims(userId: String, email: String, secret: String): String {\n val key = Keys.hmacShaKeyFor(secret.toByteArray())\n \n return Jwts.builder()\n .subject(userId)\n .claim("email", email)\n .claim("isAdmin", false)\n .issuedAt(Date())\n .expiration(Date(System.currentTimeMillis() + 3600_000))\n .signWith(key)\n .compact()\n}\n\nfun extractCustomClaim(token: String, secret: String): String? {\n val key = Keys.hmacShaKeyFor(secret.toByteArray())\n