Fiber JWT
Middleware JWT mengembalikan middleware otentikasi JSON Web Token (JWT). Untuk token yang valid, ia menetapkan pengguna di Ctx.Locals dan memanggil handler berikutnya. Untuk token yang tidak valid, ia mengembalikan error "401 - Unauthorized". Untuk token yang hilang, ia mengembalikan error "400 - Bad Request".
Catatan: Versi Go 1.19 atau lebih tinggi diperlukan
Instalasi
Middleware ini mendukung Fiber v1 dan v2, harap instal sesuai dengan perintah berikut.
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
Tanda Tangan
jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) error
Konfigurasi
Properti | Tipe | Deskripsi | Nilai Default |
---|---|---|---|
Filter | func(*fiber.Ctx) bool |
Mendefinisikan fungsi untuk melewati middleware | nil |
SuccessHandler | func(*fiber.Ctx) error |
Mendefinisikan fungsi untuk dieksekusi saat token valid | nil |
ErrorHandler | func(*fiber.Ctx, error) error |
Mendefinisikan fungsi untuk dieksekusi saat token tidak valid | 401 Invalid or expired JWT |
SigningKey | interface{} |
Kunci penandatanganan yang digunakan untuk memverifikasi token. Jika panjang SigningKeys adalah 0, ini digunakan sebagai cadangan | nil |
SigningKeys | map[string]interface{} |
Pemetaan kunci penandatanganan yang digunakan untuk memverifikasi token dengan bidang kid |
nil |
ContextKey | string |
Kunci konteks yang digunakan untuk menyimpan informasi pengguna dari token di konteks | "user" |
Claims | jwt.Claim |
Data klaim tambahan yang mendefinisikan konten token | jwt.MapClaims{} |
TokenLookup | string |
String dalam format : yang digunakan untuk mengurai token |
"header:Authorization" |
AuthScheme | string |
AuthScheme yang digunakan dalam header Authorization. Nilai default ("Bearer") digunakan hanya dengan nilai TokenLookup default |
"Bearer" |
KeyFunc | func() jwt.Keyfunc |
Fungsi yang ditentukan pengguna untuk menyediakan kunci publik untuk verifikasi token | jwtKeyFunc |
JWKSetURLs | []string |
Potongan unik URL Set Kunci Web JSON (JWK) digunakan untuk mengurai JWT | nil |
Contoh 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()
// Rute login
app.Post("/login", login)
// Rute yang dapat diakses tanpa otentikasi
app.Get("/", accessible)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{Key: []byte("secret")},
}))
// Rute terbatas
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Mengembalikan error tidak diizinkan
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Membuat klaim
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Membuat token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Menghasilkan token yang dienkripsi dan mengirimkannya sebagai respons
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("Accessible")
}
func restricted(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("Welcome " + name)
}
Uji HS256
Masuk dengan nama pengguna dan kata sandi untuk mendapatkan token.
curl --data "user=john&pass=doe" http://localhost:3000/login
Respon
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}
Permintaan sumber terbatas menggunakan token dalam header otorisasi.
curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
Respon
Selamat datang 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 (
// Jelas, ini hanya contoh uji. Jangan lakukan ini dalam produksi.
// Dalam produksi, Anda harus membuat pasangan kunci terlebih dahulu.
// Jangan pernah menambahkan kunci pribadi ke repositori GitHub mana pun.
privateKey *rsa.PrivateKey
)
func main() {
app := fiber.New()
// Untuk demonstrasi, hasilkan pasangan kunci privat/publik baru setiap kali program berjalan. Lihat catatan di atas.
rng := rand.Reader
var err error
privateKey, err = rsa.GenerateKey(rng, 2048)
if err != nil {
log.Fatalf("rsa.GenerateKey:%v", err)
}
// Rute login
app.Post("/login", login)
// Rute tanpa autentikasi
app.Get("/", accessible)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{
JWTAlg: jwtware.RS256,
Key: privateKey.Public(),
},
}))
// Rute terbatas
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Siapkan kesalahan tak terotorisasi
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Buat klaim
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Buat token
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
// Hasilkan token yang terenkripsi dan kirim sebagai respon
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("Accessible")
}
func restricted(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("Selamat datang " + name)
}
Uji RS256
RS256 pada dasarnya sama dengan uji HS256 di atas.
Uji Set JWK
Uji ini sama dengan uji JWT dasar di atas, tetapi memerlukan set kunci publik yang valid dalam format Set JWK di JWKSetURLs.
Contoh KeyFunc Kustom
KeyFunc mendefinisikan fungsi yang ditentukan pengguna untuk memberikan kunci publik untuk validasi token. Fungsi ini bertanggung jawab untuk memvalidasi algoritma tanda tangan dan memilih kunci yang tepat. Jika token diterbitkan oleh pihak eksternal, KeyFunc yang ditentukan pengguna dapat bermanfaat.
Ketika KeyFunc yang ditentukan pengguna disediakan, SigningKey, SigningKeys, dan SigningMethod akan diabaikan. Ini adalah salah satu dari tiga opsi untuk menyediakan kunci validasi token. Urutan prioritasnya adalah KeyFunc yang ditentukan pengguna, SigningKeys, dan SigningKey. Jika tidak ada SigningKeys atau SigningKey yang disediakan, fungsi ini harus disediakan. Secara defaultnya adalah untuk memvalidasi algoritma tanda tangan dan memilih kunci yang sesuai menggunakan implementasi internal.
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) {
// Periksa apakah metode tanda tangan benar
if t.Method.Alg() != jwtware.HS256 {
return nil, fmt.Errorf("Metode penandatanganan jwt tidak terduga=%v", t.Header["alg"])
}
// TODO Implementasikan muatan kunci tanda tangan kustom, misalnya, muat dari database
signingKey := "rahasia"
return []byte(signingKey), nil
}
}