جي دبليو تي
يعيد جي دبليو تي طبقة وسيطة لمصادقة رمز مفتاح JSON (JWT). بالنسبة للرمز الصالح، يضبط المستخدم في Ctx.Locals ويُشغّل المعالج التالي. أما بالنسبة للرمز غير الصالح، فإنه يُعيد خطأ "401 - غير مصرح". وبالنسبة للرمز المفقود، فإنه يُعيد خطأ "400 - طلب سيء".
ملاحظة: يتطلب Go الإصدار 1.19 أو أحدث
التثبيت
هذه الطبقة الوسيطة تدعم Fiber v1 وv2، يرجى تثبيتها وفقًا لذلك.
go get -u github.com/gofiber/fiber/v2
go get -u github.com/gofiber/contrib/jwt
go get -u github.com/golang-jwt/jwt/v5
التوقيع
jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) error
الاعدادات
الخاصية | النوع | الوصف | القيمة الافتراضية |
---|---|---|---|
Filter | func(*fiber.Ctx) bool |
يحدد وظيفة لتخطي الطبقة الوسيطة | nil |
SuccessHandler | func(*fiber.Ctx) error |
يحدد وظيفة للتنفيذ عندما يكون الرمز صالح | nil |
ErrorHandler | func(*fiber.Ctx, error) error |
يحدد وظيفة للتنفيذ عندما يكون الرمز غير صالح | 401 رمز JWT غير صالح أو منتهي الصلاحية |
SigningKey | interface{} |
مفتاح التوقيع المستخدم للتحقق من الرمز. إذا كانت طول مفاتيح التوقيع 0، يتم استخدامه كقيمة احتياطية | nil |
SigningKeys | map[string]interface{} |
إعداد مفاتيح التوقيع المستخدمة للتحقق من الرموز بحقل kid |
nil |
ContextKey | string |
المفتاح السياقي المستخدم لتخزين معلومات المستخدم من الرمز في السياق | "user" |
Claims | jwt.Claim |
بيانات المطالبات الموسعة التي تحدد محتوى الرمز | jwt.MapClaims{} |
TokenLookup | string |
سلسلة في الصيغة : تستخدم لتحليل الرمز |
"header:Authorization" |
AuthScheme | string |
مخطط الاعتماد المستخدم في رأس الاعتماد. يُستخدم القيمة الافتراضية ("Bearer") فقط مع القيمة الافتراضية لـ TokenLookup |
"Bearer" |
KeyFunc | func() jwt.Keyfunc |
وظيفة محددة من قبل المستخدم لتوفير المفتاح العام للتحقق من الرمز | jwtKeyFunc |
JWKSetURLs | []string |
مجموعة فريدة من عناوين الويب لمفاتيح JSON (JWK) المستخدمة لتحليل JWT | nil |
مثال باستخدام HS256
package main
import (
"time"
"github.com/gofiber/fiber/v2"
jwtware "github.com/gofiber/contrib/jwt"
"github.com/golang-jwt/jwt/v5"
)
func main() {
app := fiber.New()
// مسار تسجيل الدخول
app.Post("/login", login)
// مسار قابل للوصول دون مصادقة
app.Get("/", accessible)
// طبقة وسيطة JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{Key: []byte("secret")},
}))
// مسار مقيد
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// إرسال خطأ غير مصرح
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// إنشاء المطالبات
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// إنشاء الرمز
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// إنشاء الرمز المشفر وإرساله كاستجابة
t, err := token.SignedString([]byte("secret"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(fiber.Map{"token": t})
}
func accessible(c *fiber.Ctx) error {
return c.SendString("قابل للوصول")
}
func restricted(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("مرحبًا " + name)
}
اختبار HS256
تسجيل الدخول بواسطة اسم المستخدم وكلمة المرور للحصول على رمز.
curl --data "user=john&pass=doe" http://localhost:3000/login
الاستجابة
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}
طلب مورد مقيد باستخدام الرمز في رأس التفويض.
curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIأنا سعيد للمساعدة.ınR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
الاستجابة
مرحبا جون دو
package main
import (
"crypto/rand"
"crypto/rsa"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v5"
jwtware "github.com/gofiber/contrib/jwt"
)
var (
// من الواضح أن هذا مجرد مثال اختبار. لا تفعل هذا في الإنتاج.
// في الإنتاج ، يجب عليك توليد زوج المفاتيح مسبقًا.
// لا تضيف أبدا المفتاح الخاص إلى أي مستودع GitHub.
privateKey *rsa.PrivateKey
)
func main() {
app := fiber.New()
// للدليل ، قم بتوليد زوج مفتاح خاص / عام جديد في كل مرة يعمل فيها البرنامج. انظر المذكرة أعلاه.
rng := rand.Reader
var err error
privateKey, err = rsa.GenerateKey(rng, 2048)
if err != nil {
log.Fatalf("rsa.GenerateKey:%v", err)
}
// مسار تسجيل الدخول
app.Post("/login", login)
// مسار غير المصادق عليه
app.Get("/", accessible)
// برنامج وسيط JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{
JWTAlg: jwtware.RS256,
Key: privateKey.Public(),
},
}))
// مسار مقيد
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// إرسال خطأ غير مصرح به
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// إنشاء الادعاءات
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// إنشاء الرمز
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
// إنشاء الرمز المشفر وإرساله كاستجابة
t, err := token.SignedString(privateKey)
if err != nil {
log.Printf("token.SignedString:%v", err)
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(fiber.Map{"token": t})
}
func accessible(c *fiber.Ctx) error {
return c.SendString("قابل للوصول")
}
func restricted(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("مرحبا " + name)
}
اختبار RS256
RS256 في الأساس هو نفس اختبار HS256 أعلاه.
اختبار مجموعة JWK
هذه الاختبارات هي نفس اختبارات JWT الأساسية أعلاه، ولكنها تتطلب مجموعات مفاتيح عامة صالحة بتنسيق مجموعة JWK في عناوين JWKSetURLs.
مثال على دالة KeyFunc المخصصة
تحدد دالة KeyFunc دالة معرفة من قبل المستخدم يتم استخدامها لتوفير المفاتيح العمومية للتحقق من الرمز. هذه الدالة مسؤولة عن التحقق من خوارزمية التوقيع واختيار المفتاح الصحيح. إذا تم إصدار الرمز بواسطة طرف خارجي، فقد يكون استخدام KeyFunc المعرفة من قبل المستخدم ذات فائدة.
عند توفير KeyFunc معرفة من قبل المستخدم، سيتم تجاهل SigningKey، SigningKeys، وSigningMethod. هذا أحد الخيارات الثلاثة لتوفير مفاتيح التحقق من الرموز. تكون أولوية الترتيب هي KeyFunc المعرفة من قبل المستخدم، SigningKeys، وSigningKey. إذا لم يتم توفير SigningKeys أو SigningKey، يجب توفير هذه الدالة. الافتراضي هو التحقق من خوارزمية التوقيع واختيار المفتاح المناسب باستخدام التنفيذ الداخلي.
package main
import (
"fmt"
"github.com/gofiber/fiber/v2"
jwtware "github.com/gofiber/contrib/jwt"
"github.com/golang-jwt/jwt/v5"
)
func main() {
app := fiber.New()
app.Use(jwtware.New(jwtware.Config{
KeyFunc: customKeyFunc(),
}))
app.Get("/ok", func(c *fiber.Ctx) error {
return c.SendString("OK")
})
}
func customKeyFunc() jwt.Keyfunc {
return func(t *jwt.Token) (interface{}, error) {
// Check if the signature method is correct
if t.Method.Alg() != jwtware.HS256 {
return nil, fmt.Errorf("خطأ في طريقة توقيع jwt، alg=%v غير متوقع", t.Header["alg"])
}
// قم بتنفيذ تحميل مخصص للمفتاح التوقيع، على سبيل المثال، قم بتحميله من قاعدة البيانات
signingKey := "سري"
return []byte(signingKey), nil
}
}