توکن JSON Web Token (JWT)
میانافزار JWT توکن احراز هویت JSON Web Token (JWT) را برمیگرداند. برای یک توکن معتبر، کاربر را در Ctx.Locals
قرار میدهد و Handler بعدی را فراخوانی میکند. برای یک توکن نامعتبر، خطا "401 - غیرمجاز" را بر میگرداند. برای یک توکن گمشده، خطا "400 - درخواست نادرست" را بر میگرداند.
توجه: نسخه ۱.۱۹ Go یا بالاتر مورد نیاز است
نصب
این میانافزار 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{} |
کلید امضا برای تأیید توکن. اگر طول SigningKeys برابر ۰ باشد، بهعنوان یک نقش برمیگردد | nil |
SigningKeys | map[string]interface{} |
نگاشت کلیدهای امضا برای تأیید توکنها با یک فیلد kid |
nil |
ContextKey | string |
کلید متناوب از کاربر برای ذخیره اطلاعات توکن در متناوب | "user" |
Claims | jwt.Claim |
دادههای ادعاهای توکن گسترش یافته که محتوای توکن را تعیین میکند | jwt.MapClaims{} |
TokenLookup | string |
یک رشته با فرمت : برای تجزیه توکن استفاده میشود |
"header:Authorization" |
AuthScheme | string |
AuthScheme مورد استفاده در هدر Authorization. مقدار پیشفرض ("Bearer") فقط با مقدار پیشفرض TokenLookup استفاده میشود |
"Bearer" |
KeyFunc | func() jwt.Keyfunc |
تابع تعریفشده توسط کاربر برای ارائه کلید عمومی برای تأیید توکن | jwtKeyFunc |
JWKSetURLs | []string |
یک آرایه از URLهای یکتای مجموعه کلید JSON Web (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("رمز")},
}))
// مسیر محدود شده
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": "جان دو",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// ایجاد توکن
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// تولید توکن رمزنگاری شده و ارسال به عنوان پاسخ
t, err := token.SignedString([]byte("رمز"))
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 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
پاسخ
Welcome John Doe
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 Set
این آزمونها همانند آزمونهای JWT پایهای بالا هستند، اما نیازمند مجموعه کلید عمومی معتبر به فرمت JWK Set در JWKSetURLs هستند.
مثال تابع کلید سفارشی
تابع 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) {
// بررسی اینکه روش امضا صحیح باشد
if t.Method.Alg() != jwtware.HS256 {
return nil, fmt.Errorf("روش امضای jwt غیرمنتظره است=%v", t.Header["alg"])
}
// اجرای بارگیری سفارشی کلید امضا، برای مثال، بارگیری از پایگاه داده
signingKey := "رمز"
return []byte(signingKey), nil
}
}