تهدف JJWT إلى أن تكون المكتبة الأسهل استخدامًا وفهمًا لإنشاء JSON Web Tokens (JWTs) وJSON Web Keys (JWKs) والتحقق منها على JVM وAndroid.
JJWT هو تطبيق Java خالص يعتمد حصريًا على مواصفات JOSE Working Group RFC:
RFC 7519: رمز ويب JSON (JWT)
RFC 7515: توقيع ويب JSON (JWS)
RFC 7516: تشفير الويب JSON (JWE)
RFC 7517: مفتاح ويب JSON (JWK)
RFC 7518: خوارزميات الويب JSON (JWA)
RFC 7638: بصمة الإبهام لمفتاح الويب JSON
RFC 9278: URI لبصمة الإبهام لمفتاح الويب JSON
RFC 7797: خيار الحمولة غير المشفرة لـ JWS
RFC 8037: خوارزميات منحنى إدواردز وJWKs
تم إنشاؤه بواسطة Les Hazlewood ويتم دعمه وصيانته من قبل مجتمع المساهمين.
JJWT مفتوح المصدر بموجب شروط ترخيص Apache 2.0.
PublicKey
JWK العام الخاصtoString()
السلامةيعمل بكامل طاقته على جميع إصدارات Java 7+ JDKs وAndroid
أفضل ممارسات وتأكيدات الأمان التلقائي
سهلة التعلم وقراءة API
واجهات سهلة الاستخدام وقابلة للقراءة، وهي رائعة للإكمال التلقائي لـ IDE لكتابة التعليمات البرمجية بسرعة
متوافق تمامًا مع مواصفات RFC في جميع الوظائف المنفذة، وتم اختباره مقابل ناقلات الاختبار المحددة من قبل RFC
تنفيذ مستقر مع ما يقرب من 1700 اختبار وتغطية كود الاختبار بنسبة 100%. يتم اختبار كل طريقة وبيان ومتغير فرعي شرطي في قاعدة التعليمات البرمجية بأكملها ويُطلب منها تمرير كل إصدار.
إنشاء وتحليل والتحقق من JWTs المدمجة الموقعة رقميًا (المعروفة أيضًا باسم JWSs) باستخدام جميع خوارزميات JWS القياسية:
المعرف | خوارزمية التوقيع |
---|---|
| HMAC باستخدام SHA-256 |
| HMAC باستخدام SHA-384 |
| HMAC باستخدام SHA-512 |
| ECDSA باستخدام P-256 وSHA-256 |
| ECDSA باستخدام P-384 وSHA-384 |
| ECDSA باستخدام P-521 وSHA-512 |
| RSASSA-PKCS-v1_5 باستخدام SHA-256 |
| RSASSA-PKCS-v1_5 باستخدام SHA-384 |
| RSASSA-PKCS-v1_5 باستخدام SHA-512 |
| RSASSA-PSS باستخدام SHA-256 وMGF1 مع SHA-256 1 |
| RSASSA-PSS باستخدام SHA-384 وMGF1 مع SHA-384 1 |
| RSASSA-PSS باستخدام SHA-512 وMGF1 مع SHA-512 1 |
| خوارزمية التوقيع الرقمي لمنحنى إدواردز 2 |
1. يتطلب Java 11 أو موفر JCA متوافقًا (مثل BouncyCastle) في مسار فئة وقت التشغيل.
2 . يتطلب Java 15 أو موفر JCA متوافقًا (مثل BouncyCastle) في مسار فئة وقت التشغيل.
إنشاء وتحليل وفك تشفير JWTs المضغوطة المشفرة (المعروفة أيضًا باسم JWEs) باستخدام جميع خوارزميات تشفير JWE القياسية:
المعرف | خوارزمية التشفير |
---|---|
| AES_128_CBC_HMAC_SHA_256 خوارزمية التشفير المصادق عليها |
| AES_192_CBC_HMAC_SHA_384 خوارزمية التشفير المعتمدة |
| AES_256_CBC_HMAC_SHA_512 خوارزمية التشفير المعتمدة |
| AES GCM باستخدام مفتاح 128 بت 1 |
| AES GCM باستخدام مفتاح 192 بت 1 |
| AES GCM باستخدام مفتاح 256 بت 1 |
1 . يتطلب Java 8 أو موفر JCA متوافقًا (مثل BouncyCastle) في مسار فئة وقت التشغيل.
جميع خوارزميات إدارة المفاتيح للحصول على مفاتيح تشفير وفك تشفير JWE:
المعرف | خوارزمية إدارة المفاتيح |
---|---|
| RSAES-PKCS1-v1_5 |
| RSAES OAEP باستخدام المعلمات الافتراضية |
| RSAES OAEP باستخدام SHA-256 وMGF1 مع SHA-256 |
| AES Key Wrap مع القيمة الأولية الافتراضية باستخدام مفتاح 128 بت |
| AES Key Wrap مع القيمة الأولية الافتراضية باستخدام مفتاح 192 بت |
| AES Key Wrap مع القيمة الأولية الافتراضية باستخدام مفتاح 256 بت |
| الاستخدام المباشر للمفتاح المتماثل المشترك مثل CEK |
| المنحنى الإهليلجي Diffie-Hellman اتفاقية رئيسية ثابتة سريعة الزوال باستخدام Concat KDF |
| ECDH-ES باستخدام Concat KDF وCEK ملفوف بـ "A128KW" |
| ECDH-ES باستخدام Concat KDF وCEK ملفوف بـ "A192KW" |
| ECDH-ES باستخدام Concat KDF وCEK ملفوف بـ "A256KW" |
| التفاف المفتاح باستخدام AES GCM باستخدام مفتاح 128 بت 1 |
| التفاف المفتاح باستخدام AES GCM باستخدام مفتاح 192 بت 1 |
| التفاف المفتاح باستخدام AES GCM باستخدام مفتاح 256 بت 1 |
| PBES2 مع غلاف HMAC SHA-256 و"A128KW" 1 |
| PBES2 مع غلاف HMAC SHA-384 و"A192KW" 1 |
| PBES2 مع غلاف HMAC SHA-512 و"A256KW" 1 |
1 . يتطلب Java 8 أو موفر JCA متوافقًا (مثل BouncyCastle) في مسار فئة وقت التشغيل.
إنشاء مفاتيح ويب JSON (JWKs) وتحليلها والتحقق منها بجميع تنسيقات مفاتيح JWA القياسية باستخدام أنواع Key
Java الأصلية:
تنسيق مفتاح JWK | نوع Key جافا | نوع JJWT Jwk |
---|---|---|
مفتاح متماثل | | |
المفتاح العام للمنحنى الإهليلجي | | |
المفتاح الخاص للمنحنى الإهليلجي | | |
مفتاح RSA العام | | |
مفتاح RSA الخاص | | |
مفتاح XDH الخاص | | |
مفتاح XDH الخاص | | |
EdDSA المفتاح العام | | |
مفتاح EdDSA الخاص | | |
1 . يتطلب Java 15 أو موفر JCA متوافقًا (مثل BouncyCastle) في مسار فئة وقت التشغيل.
2 . يتطلب Java 15 أو موفر JCA متوافقًا (مثل BouncyCastle) في مسار فئة وقت التشغيل.
تحسينات الراحة تتجاوز المواصفات مثل
ضغط الحمولة لأي JWT كبير، وليس فقط JWEs
تأكيدات المطالبات (التي تتطلب قيما محددة)
المطالبة بتنظيم POJO وإلغاء تنظيمه عند استخدام محلل JSON متوافق (مثل Jackson)
إنشاء المفتاح الآمن بناءً على خوارزميات JWA المطلوبة
وأكثر…
التسلسل والتحليل غير المضغوط.
قد يتم تنفيذ هذه الميزة في إصدار مستقبلي. مساهمات المجتمع هي موضع ترحيب!
إذا كانت لديك مشكلة في استخدام JJWT، فيرجى أولاً قراءة الوثائق الموجودة على هذه الصفحة قبل طرح الأسئلة. نحن نحاول جاهدين التأكد من أن وثائق JJWT قوية ومصنفة بجدول محتويات ومحدثة لكل إصدار.
إذا كانت الوثائق أو API JavaDoc غير كافية، وكانت لديك أسئلة حول قابلية الاستخدام أو كنت في حيرة بشأن شيء ما، فيرجى طرح سؤالك هنا. لكن:
من فضلك لا تقم بإنشاء مشكلة GitHub لطرح سؤال.
نحن نستخدم مشكلات GitHub لتتبع العمل القابل للتنفيذ الذي يتطلب إجراء تغييرات على تصميم JJWT و/أو قاعدة التعليمات البرمجية. إذا كان لديك سؤال حول قابلية الاستخدام، فبدلاً من ذلك، يرجى طرح سؤالك هنا، ويمكننا تحويله إلى مشكلة إذا لزم الأمر.
إذا تم إنشاء مشكلة GitHub التي لا تمثل عملاً قابلاً للتنفيذ لقاعدة تعليمات JJWT، فسيتم إغلاقها على الفور.
إذا لم يكن لديك سؤال حول قابلية الاستخدام وتعتقد أن لديك خطأ مشروعًا أو طلب ميزة، فيرجى مناقشته هنا أولاً . يرجى إجراء بحث سريع أولاً لمعرفة ما إذا كانت هناك مناقشة موجودة تتعلق بمناقشةك موجودة بالفعل والانضمام إلى تلك المناقشة الحالية إذا لزم الأمر.
إذا كنت تشعر أنك ترغب في المساعدة في إصلاح خطأ ما أو تنفيذ الميزة الجديدة بنفسك، فيرجى قراءة قسم المساهمة التالي قبل البدء في أي عمل.
طلبات السحب البسيطة التي تعمل على إصلاح أي شيء آخر غير كود JJWT الأساسي (الوثائق، JavaDoc، الأخطاء المطبعية، حالات الاختبار، وما إلى ذلك) تحظى بالتقدير دائمًا ولديها احتمالية كبيرة لدمجها بسرعة. من فضلك أرسلهم!
ومع ذلك، إذا كنت تريد أو تشعر بالحاجة إلى تغيير وظيفة JJWT أو الكود الأساسي، فيرجى عدم إصدار طلب سحب دون بدء مناقشة JJWT جديدة ومناقشة التغييرات المطلوبة أولاً ، قبل البدء في العمل عليها .
سيكون من العار رفض طلب السحب الجاد والمقدر حقًا إذا كان لا يتوافق مع أهداف المشروع أو توقعات التصميم أو الوظائف المخطط لها. لقد اضطررنا للأسف إلى رفض العلاقات العامة الكبيرة في الماضي لأنها كانت غير متزامنة مع توقعات المشروع أو التصميم - كل ذلك لأن مؤلف العلاقات العامة لم يقم أولاً بالتواصل مع الفريق أولاً قبل العمل على الحل.
لذا، يرجى إنشاء مناقشة JJWT جديدة أولاً للمناقشة، وبعد ذلك يمكننا أن نرى بسهولة تحويل المناقشة إلى مشكلة ثم معرفة ما إذا كان (أو كيف) هناك ما يبرر العلاقات العامة. شكرًا لك!
إذا كنت ترغب في المساعدة، ولكنك لا تعرف من أين تبدأ، فيرجى زيارة صفحة المشكلات المطلوبة للمساعدة واختيار أي منها، وسنكون سعداء بمناقشة الأسئلة والإجابة عليها في تعليقات المشكلة.
إذا كان أي من هؤلاء لا يروق لك، فلا تقلق! سيكون موضع تقدير أي مساعدة ترغب في تقديمها بناءً على التحذيرات المذكورة أعلاه فيما يتعلق بطلبات السحب المساهمة. لا تتردد في مناقشة أو طرح الأسئلة أولا إذا لم تكن متأكدا. :)
JSON Web Token (JWT) هو تنسيق مراسلة نصية للأغراض العامة لنقل المعلومات بطريقة مدمجة وآمنة. خلافًا للاعتقاد الشائع، فإن JWT ليس مفيدًا فقط لإرسال واستقبال رموز الهوية على الويب - حتى لو كانت هذه هي حالة الاستخدام الأكثر شيوعًا. يمكن استخدام JWTs كرسائل لأي نوع من البيانات.
يحتوي JWT في أبسط صوره على جزأين:
البيانات الأولية داخل JWT، تسمى payload
، و
Object
JSON يحتوي على أزواج اسم/قيمة تمثل بيانات وصفية حول payload
والرسالة نفسها، تسمى header
.
يمكن أن تكون payload
JWT أي شيء على الإطلاق - أي شيء يمكن تمثيله كمصفوفة بايت، مثل السلاسل والصور والمستندات وما إلى ذلك.
ولكن نظرًا لأن header
JWT هو Object
JSON، فمن المنطقي أن تكون payload
JWT أيضًا Object
JSON أيضًا. في كثير من الحالات، يفضل المطورون أن تكون payload
عبارة عن JSON تمثل بيانات حول مستخدم أو جهاز كمبيوتر أو مفهوم هوية مشابه. عند استخدامها بهذه الطريقة، تسمى payload
بكائن Claims
JSON، ويسمى كل زوج من الاسم/القيمة داخل هذا الكائن claim
- كل جزء من المعلومات ضمن "مطالبات" بشيء يتعلق بالهوية.
وعلى الرغم من أنه من المفيد "المطالبة" بشيء يتعلق بالهوية، إلا أن أي شخص يمكنه فعل ذلك. المهم هو أن تثق في المطالبات من خلال التحقق من أنها واردة من شخص أو جهاز كمبيوتر تثق به.
من الميزات الرائعة لـ JWTs أنه يمكن تأمينها بطرق مختلفة. يمكن توقيع JWT بطريقة مشفرة (مما يجعلها ما نسميه JWS) أو مشفرة (مما يجعلها JWE). يضيف هذا طبقة قوية من إمكانية التحقق إلى JWT - يمكن لمستلم JWS أو JWE أن يتمتع بدرجة عالية من الثقة أنها تأتي من شخص يثق به من خلال التحقق من التوقيع أو فك تشفيره. إن ميزة التحقق هذه هي التي تجعل JWT خيارًا جيدًا لإرسال واستقبال المعلومات الآمنة، مثل مطالبات الهوية.
أخيرًا، يعد JSON المزود بمسافة بيضاء لسهولة القراءة البشرية أمرًا رائعًا، لكنه لا يصلح لتنسيق رسالة فعال للغاية. لذلك، يمكن ضغط JWTs (وحتى ضغطها) إلى الحد الأدنى من التمثيل - بشكل أساسي سلاسل مشفرة بـ Base64URL - بحيث يمكن نقلها عبر الويب بشكل أكثر كفاءة، كما هو الحال في رؤوس HTTP أو عناوين URL.
بمجرد حصولك على payload
header
، كيف يتم ضغطهما لنقل الويب، وكيف يبدو شكل JWT النهائي فعليًا؟ دعونا نستعرض نسخة مبسطة من العملية باستخدام بعض الأكواد الزائفة:
لنفترض أن لدينا JWT header
JSON وحمولة رسالة نصية بسيطة:
header
{ "ألغ": "لا شيء" }
حمولة
العلامة الحقيقية للذكاء ليست المعرفة بل الخيال.
قم بإزالة جميع المسافات البيضاء غير الضرورية في JSON:
String header = ' {"alg":"none"} '
String payload = ' The true sign of intelligence is not knowledge but imagination. '
احصل على بايتات UTF-8 وترميز Base64URL لكل منهما:
String encodedHeader = base64URLEncode( header . getBytes( " UTF-8 " ) )
String encodedPayload = base64URLEncode( payload . getBytes( " UTF-8 " ) )
انضم إلى الرأس المشفر والمطالبات باستخدام أحرف النقطة ('.'):
String compact = encodedHeader + ' . ' + encodedPayload + ' . '
تبدو سلسلة JWT compact
النهائية كما يلي:
eyJhbGciOiJub25lIn0.VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u.
يُطلق على هذا اسم JWT "غير المحمي" لأنه لم يكن هناك أي أمان - لا توجد توقيعات رقمية أو تشفير "لحماية" JWT لضمان عدم إمكانية تغييره بواسطة أطراف ثالثة.
إذا أردنا التوقيع رقميًا على النموذج المضغوط حتى نتمكن على الأقل من ضمان عدم قيام أي شخص بتغيير البيانات دون أن نكتشفها، فسيتعين علينا تنفيذ بضع خطوات إضافية، كما هو موضح أدناه.
بدلاً من حمولة النص العادي، ربما يستخدم المثال التالي النوع الأكثر شيوعًا من الحمولة - Object
يدعي JSON يحتوي على معلومات حول هوية معينة. سنقوم أيضًا بالتوقيع رقميًا على JWT لضمان عدم إمكانية تغييره بواسطة طرف ثالث دون علمنا.
لنفترض أن لدينا header
JSON payload
مطالبات:
header
{
"alg" : " HS256 "
}
حمولة
{
"sub" : " Joe "
}
في هذه الحالة، يشير header
إلى أنه سيتم استخدام خوارزمية HS256
(HMAC باستخدام SHA-256) لتوقيع JWT بشكل مشفر. أيضًا، يحتوي كائن payload
JSON على مطالبة واحدة، sub
بقيمة Joe
.
يوجد عدد من المطالبات القياسية، تسمى المطالبات المسجلة، في المواصفات sub
(لـ "الموضوع") هي واحدة منها.
قم بإزالة جميع المسافات البيضاء غير الضرورية في كلا كائني JSON:
String header = ' {"alg":"HS256"} '
String claims = ' {"sub":"Joe"} '
احصل على بايتات UTF-8 وتشفير Base64URL لكل منهما:
String encodedHeader = base64URLEncode( header . getBytes( " UTF-8 " ) )
String encodedClaims = base64URLEncode( claims . getBytes( " UTF-8 " ) )
قم بتسلسل الرأس المشفر والمطالبات بحرف النقطة '.' المحدد:
String concatenated = encodedHeader + ' . ' + encodedClaims
استخدم سرًا مشفرًا أو مفتاحًا خاصًا قويًا بدرجة كافية، بالإضافة إلى خوارزمية توقيع من اختيارك (سنستخدم HMAC-SHA-256 هنا)، وقم بتوقيع السلسلة المتسلسلة:
SecretKey key = getMySecretKey()
byte [] signature = hmacSha256( concatenated, key )
نظرًا لأن التوقيعات تكون دائمًا عبارة عن صفائف بايت، يقوم Base64URL بتشفير التوقيع وضمه إلى السلسلة concatenated
باستخدام حرف النقطة '.' المحدد:
String compact = concatenated + ' . ' + base64URLEncode( signature )
والآن، تبدو السلسلة compact
النهائية كما يلي:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4
وهذا ما يسمى "JWS" - وهو اختصار لـ JWT الموقع .
بالطبع، لا أحد يرغب في القيام بذلك يدويًا من خلال التعليمات البرمجية، والأسوأ من ذلك، إذا ارتكبت أي خطأ، فقد تؤدي إلى حدوث مشكلات أمنية ونقاط ضعف خطيرة. ونتيجة لذلك، تم إنشاء JJWT للتعامل مع كل هذا نيابةً عنك: يقوم JJWT بأتمتة إنشاء JWSs والتحليل والتحقق من JWSs نيابةً عنك.
لقد رأينا حتى الآن JWT غير محمي وJWT موقّع بالتشفير (يُسمى "JWS"). أحد الأشياء المتأصلة في هذين الاثنين هو أن جميع المعلومات الموجودة بداخلهما يمكن لأي شخص رؤيتها - جميع البيانات الموجودة في كل من الرأس والحمولة مرئية للعامة. يضمن JWS فقط عدم تغيير البيانات من قبل أي شخص - ولا يمنع أي شخص من رؤيتها. في كثير من الأحيان، يكون هذا أمرًا جيدًا لأن البيانات الموجودة فيها ليست معلومات حساسة.
ولكن ماذا لو كنت بحاجة إلى تمثيل المعلومات في JWT التي تعتبر معلومات حساسة - ربما العنوان البريدي لشخص ما أو رقم الضمان الاجتماعي أو رقم الحساب المصرفي؟
في هذه الحالات، نرغب في الحصول على JWT مشفر بالكامل، يسمى "JWE" للاختصار. يستخدم JWE التشفير للتأكد من أن الحمولة تظل مشفرة ومصادق عليها بالكامل بحيث لا تتمكن الأطراف غير المصرح لها من رؤية البيانات الموجودة بداخلها، ولا تغيير البيانات دون أن يتم اكتشافها. على وجه التحديد، تتطلب مواصفات JWE استخدام التشفير المصادق مع خوارزميات البيانات المرتبطة لتشفير البيانات وحمايتها بشكل كامل.
نظرة عامة كاملة على خوارزميات AEAD خارج نطاق هذه الوثائق، ولكن فيما يلي مثال على JWE المضغوط النهائي الذي يستخدم هذه الخوارزميات (فواصل الأسطر مخصصة لسهولة القراءة فقط):
eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0. 6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDThzBC2IlrT1oOQ. AxY8DCtDaGlsbGljb3RoZQ. KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY. U0m_YmjN04DJvceFICbCVQ
سنغطي بعد ذلك كيفية تثبيت JJWT في مشروعك، وبعد ذلك سنرى كيفية استخدام واجهة برمجة تطبيقات JJWT الرائعة بدلاً من معالجة السلاسل المحفوفة بالمخاطر لإنشاء JWTs وJWSs وJWEs بسرعة وأمان.
استخدم أداة البناء المتوافقة مع Maven المفضلة لديك لسحب التبعيات من Maven Central.
قد تختلف التبعيات قليلًا إذا كنت تعمل مع مشروع JDK أو مشروع Android.
إذا كنت تقوم بإنشاء مشروع JDK (غير Android)، فستحتاج إلى تحديد التبعيات التالية:
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-api</ artifactId >
< version >0.12.6</ version >
</ dependency >
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-impl</ artifactId >
< version >0.12.6</ version >
< scope >runtime</ scope >
</ dependency >
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-jackson</ artifactId > <!-- or jjwt-gson if Gson is preferred -->
< version >0.12.6</ version >
< scope >runtime</ scope >
</ dependency >
<!-- Uncomment this next dependency if you are using:
- JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
It is unnecessary for these algorithms on JDK 15 or later.
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId> or bcprov-jdk15to18 on JDK 7
<version>1.76</version>
<scope>runtime</scope>
</dependency>
-->
dependencies {
implementation ' io.jsonwebtoken:jjwt-api:0.12.6 '
runtimeOnly ' io.jsonwebtoken:jjwt-impl:0.12.6 '
runtimeOnly ' io.jsonwebtoken:jjwt-jackson:0.12.6 ' // or 'io.jsonwebtoken:jjwt-gson:0.12.6' for gson
/*
Uncomment this next dependency if you are using:
- JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
It is unnecessary for these algorithms on JDK 15 or later.
*/
// runtimeOnly 'org.bouncycastle:bcprov-jdk18on:1.76' // or bcprov-jdk15to18 on JDK 7
}
ستحتاج مشاريع Android إلى تحديد التبعيات التالية واستثناءات Proguard Provider
BouncyCastle الاختياري:
أضف التبعيات إلى مشروعك:
dependencies {
api( ' io.jsonwebtoken:jjwt-api:0.12.6 ' )
runtimeOnly( ' io.jsonwebtoken:jjwt-impl:0.12.6 ' )
runtimeOnly( ' io.jsonwebtoken:jjwt-orgjson:0.12.6 ' ) {
exclude( group : ' org.json ' , module : ' json ' ) // provided by Android natively
}
/*
Uncomment this next dependency if you want to use:
- RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
** AND ALSO ensure you enable the BouncyCastle provider as shown below **
*/
// implementation('org.bouncycastle:bcprov-jdk18on:1.76') // or bcprov-jdk15to18 for JDK 7
}
يمكنك استخدام قواعد استبعاد Android Proguard التالية:
- حافظ على السمات InnerClasses - احتفظ بالفصل io.jsonwebtoken.** { *; } -keepnames class io.jsonwebtoken.* { *; } - واجهة الاحتفاظ بالأسماء io.jsonwebtoken.* { *; } -keep class org.bouncycastle.** { *; } -keepnames class org.bouncycastle.** { *; } -dontwarn org.bouncycastle.**
إذا كنت تريد استخدام خوارزميات JWT RSASSA-PSS (على سبيل المثال PS256
و PS384
و PS512
)، أو EdECDH ( X25512
أو X448
) Elliptic Curve Diffie-Hellman، أو خوارزميات توقيع EdDSA ( Ed25519
أو Ed448
)، أو كنت تريد فقط التأكد من أن جهاز Android الخاص بك يقوم التطبيق بتشغيل إصدار محدث من BouncyCastle، وسوف تحتاج إلى:
قم بإلغاء التعليق على تبعية BouncyCastle كما تم التعليق عليه أعلاه في قسم التبعيات.
استبدل موفر BC
المخصص لنظام Android القديم بالموفر المحدث.
يجب أن يتم تسجيل الموفر في وقت مبكر من دورة حياة التطبيق، ويفضل أن يكون ذلك في فئة Activity
الرئيسية لتطبيقك ككتلة تهيئة ثابتة. على سبيل المثال:
class MainActivity : AppCompatActivity () {
companion object {
init {
Security .removeProvider( " BC " ) // remove old/legacy Android-provided BC provider
Security .addProvider( BouncyCastleProvider ()) // add 'real'/correct BC provider
}
}
// ... etc ...
}
لاحظ أن إعلانات تبعيات JJWT المذكورة أعلاه تحتوي جميعها على تبعية واحدة فقط في وقت الترجمة ويتم الإعلان عن الباقي كتبعيات وقت التشغيل .
وذلك لأن JJWT مصمم بحيث تعتمد فقط على واجهات برمجة التطبيقات (APIs) المصممة بشكل صريح لتستخدمها في تطبيقاتك وجميع تفاصيل التنفيذ الداخلي الأخرى - التي يمكن أن تتغير دون سابق إنذار - يتم نقلها إلى تبعيات وقت التشغيل فقط. هذه نقطة مهمة للغاية إذا كنت تريد ضمان استخدام JJWT المستقر والترقيات بمرور الوقت:
يضمن JJWT توافق الإصدارات الدلالية لجميع عناصره باستثناء |
يتم ذلك لمصلحتك: يتم بذل عناية كبيرة في تنظيم jjwt-api
.jar والتأكد من أنه يحتوي على ما تحتاجه ويظل متوافقًا مع الإصدارات السابقة قدر الإمكان حتى تتمكن من الاعتماد عليه بأمان باستخدام نطاق الترجمة. توفر إستراتيجية وقت التشغيل jjwt-impl
.jar لمطوري JJWT المرونة اللازمة لتغيير الحزم الداخلية والتطبيقات متى وكيفما كان ذلك ضروريًا. ويساعدنا ذلك في تنفيذ الميزات وإصلاح الأخطاء وإرسال الإصدارات الجديدة إليك بسرعة وكفاءة أكبر.
يتم إخفاء معظم التعقيدات خلف واجهة سهلة الاستخدام وقابلة للقراءة ومعتمدة على المنشئ، وهي رائعة للاعتماد على الإكمال التلقائي لـ IDE لكتابة التعليمات البرمجية بسرعة. هنا مثال:
import io . jsonwebtoken . Jwts ;
import io . jsonwebtoken . security . Keys ;
import java . security . Key ;
// We need a signing key, so we'll create one just for this example. Usually
// the key would be read from your application configuration instead.
SecretKey key = Jwts . SIG . HS256 . key (). build ();
String jws = Jwts . builder (). subject ( "Joe" ). signWith ( key ). compact ();
كم كان ذلك سهلاً!؟
وفي هذه الحالة نحن:
إنشاء JWT الذي سيتم تعيين المطالبة sub
(الموضوع) المسجلة عليه على Joe
. نحن إذن
توقيع JWT باستخدام مفتاح مناسب لخوارزمية HMAC-SHA-256. وأخيرا، نحن
ضغطها في شكل String
النهائي. يُطلق على JWT المُوقع اسم "JWS".
تبدو سلسلة jws
الناتجة كما يلي:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4
لنتحقق الآن من JWT (يجب عليك دائمًا تجاهل JWTs التي لا تتطابق مع التوقيع المتوقع):
assert Jwts . parser (). verifyWith ( key ). build (). parseSignedClaims ( jws ). getPayload (). getSubject (). equals ( "Joe" );
هناك شيئان يحدثان هنا. يتم استخدام key
السابق للتحقق من توقيع JWT. إذا فشل في التحقق من JWT، فسيتم طرح SignatureException
(الذي يمتد JwtException
). بافتراض أنه تم التحقق من JWT، فإننا نقوم بتحليل المطالبات ونؤكد أن هذا الموضوع تم تعيينه على Joe
. عليك أن تحب العبارات المفردة التي تحتوي على الكثير من التعليمات البرمجية!
ملحوظة | JWTs الآمنة للنوع: للحصول على نتيجة JWT |
ولكن ماذا لو فشل التحليل أو التحقق من صحة التوقيع؟ يمكنك التقاط JwtException
والرد وفقًا لذلك:
try {
Jwts . parser (). verifyWith ( key ). build (). parseSignedClaims ( compactJws );
//OK, we can trust this JWT
} catch ( JwtException e ) {
//don't trust the JWT!
}
الآن بعد أن حصلنا على "تجربة" سريعة حول كيفية إنشاء JWTs وتحليلها، فلنغطي واجهة برمجة التطبيقات الخاصة بـ JJWT بشكل متعمق.
يمكنك إنشاء JWT كما يلي:
استخدم طريقة Jwts.builder()
لإنشاء مثيل JwtBuilder
.
اختياريًا، قم بتعيين أي معلمات header
حسب الرغبة.
استدعاء أساليب البناء لتعيين محتوى الحمولة أو المطالبات.
يمكنك اختياريًا استدعاء أساليب signWith
أو encryptWith
إذا كنت تريد توقيع JWT أو تشفيره رقميًا.
قم باستدعاء الطريقة compact()
لإنتاج سلسلة JWT المدمجة الناتجة.
على سبيل المثال:
String jwt = Jwts . builder () // (1)
. header () // (2) optional
. keyId ( "aKeyId" )
. and ()
. subject ( "Bob" ) // (3) JSON Claims, or
//.content(aByteArray, "text/plain") // any byte[] content, with media type
. signWith ( signingKey ) // (4) if signing, or
//.encryptWith(key, keyAlg, encryptionAlg) // if encrypting
. compact (); // (5)
قد تكون payload
JWT إما محتوى byte[]
(عبر content
) أو مطالبات JSON (مثل subject
claims
وما إلى ذلك)، ولكن ليس كليهما.
يمكن استخدام التوقيعات الرقمية ( signWith
) أو التشفير ( encryptWith
)، ولكن ليس كليهما.
JWTs غير المحمية : إذا لم تستخدم أساليب الإنشاء |
رأس JWT هو Object
JSON يوفر بيانات تعريف حول المحتويات والتنسيق وأي عمليات تشفير ذات صلة payload
JWT. يوفر JJWT عددًا من الطرق لتعيين الرأس بالكامل و/أو معلمات الرأس الفردية المتعددة (أزواج الاسم/القيمة).
الطريقة الأسهل والموصى بها لتعيين واحد أو أكثر من معلمات رأس JWT (أزواج الاسم/القيمة) هي استخدام منشئ JwtBuilder
's header()
حسب الرغبة، ثم استدعاء الأسلوب and()
الخاص به للعودة إلى JwtBuilder
لمزيد من التكوين . على سبيل المثال:
String jwt = Jwts . builder ()
. header () // <----
. keyId ( "aKeyId" )
. x509Url ( aUri )
. add ( "someName" , anyValue )
. add ( mapValues )