Fiber JWT
Il middleware JWT restituisce un middleware di autenticazione JSON Web Token (JWT). Per un token valido, imposta l'utente in Ctx.Locals e chiama il gestore successivo. Per un token non valido, restituisce un errore "401 - Non autorizzato". Per un token mancante, restituisce un errore "400 - Richiesta non valida".
Nota: È richiesta la versione Go 1.19 o successiva
Installazione
Questo middleware supporta Fiber v1 e v2, installare di conseguenza.
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
Firma
jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) error
Configurazione
Proprietà | Tipo | Descrizione | Valore predefinito |
---|---|---|---|
Filter | func(*fiber.Ctx) bool |
Definisce una funzione per saltare il middleware | nil |
SuccessHandler | func(*fiber.Ctx) error |
Definisce una funzione da eseguire al token valido | nil |
ErrorHandler | func(*fiber.Ctx, error) error |
Definisce una funzione da eseguire al token non valido | 401 JWT non valido o scaduto |
SigningKey | interface{} |
La chiave di firma utilizzata per verificare il token. Se la lunghezza di SigningKeys è 0, viene utilizzata come fallback | nil |
SigningKeys | map[string]interface{} |
Mappatura delle chiavi di firma utilizzate per verificare i token con un campo kid |
nil |
ContextKey | string |
La chiave di contesto utilizzata per memorizzare le informazioni dell'utente dal token nel contesto | "user" |
Claims | jwt.Claim |
Dati estesi delle rivendicazioni che definiscono il contenuto del token | jwt.MapClaims{} |
TokenLookup | string |
Una stringa nel formato : utilizzata per analizzare il token |
"header:Authorization" |
AuthScheme | string |
L'AuthScheme utilizzato nell'intestazione di autorizzazione. Il valore predefinito ("Bearer") è utilizzato solo con il valore predefinito TokenLookup |
"Bearer" |
KeyFunc | func() jwt.Keyfunc |
Una funzione definita dall'utente per fornire la chiave pubblica per la verifica del token | jwtKeyFunc |
JWKSetURLs | []string |
Una sequenza di URL univoci del JSON Web Key (JWK) Set utilizzati per analizzare JWT | nil |
Esempio di 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()
// Percorso di accesso
app.Post("/login", login)
// Percorso accessibile senza autenticazione
app.Get("/", accessible)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{Key: []byte("segreto")},
}))
// Percorso limitato
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Lancio di un errore di autorizzazione
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Creazione delle rivendicazioni
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Creazione del token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Generazione del token codificato e invio come risposta
t, err := token.SignedString([]byte("segreto"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(fiber.Map{"token": t})
}
func accessible(c *fiber.Ctx) error {
return c.SendString("Accessibile")
}
func restricted(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("Benvenuto " + name)
}
Test HS256
Accedi con nome utente e password per ottenere un token.
curl --data "user=john&pass=doe" http://localhost:3000/login
Risposta
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}
Richiesta per accedere a una risorsa limitata utilizzando il token nell'intestazione di autorizzazione.
curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
Risposta
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 (
// Ovviamente, questo è solo un esempio di test. Non farlo in produzione.
// In produzione, è necessario generare preventivamente la coppia di chiavi.
// Non aggiungere mai la chiave privata a un repository GitHub.
privateKey *rsa.PrivateKey
)
func main() {
app := fiber.New()
// Per scopi dimostrativi, genera una nuova coppia di chiavi privata/pubblica ogni volta che il programma viene eseguito. Vedi la nota sopra.
rng := rand.Reader
var err error
privateKey, err = rsa.GenerateKey(rng, 2048)
if err != nil {
log.Fatalf("rsa.GenerateKey:%v", err)
}
// Percorso di accesso
app.Post("/login", login)
// Percorso non autenticato
app.Get("/", accessibile)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{
JWTAlg: jwtware.RS256,
Key: privateKey.Public(),
},
}))
// Percorso limitato
app.Get("/restricted", limitato)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Genera errore non autorizzato
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Crea affermazioni
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Crea token
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
// Genera token codificato e invialo come risposta
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 accessibile(c *fiber.Ctx) error {
return c.SendString("Accessibile")
}
func limitato(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("Welcome " + name)
}
Test RS256
RS256 è essenzialmente lo stesso del test HS256 sopra.
Test JWK Set
Questi test sono gli stessi dei test JWT di base sopra, ma richiedono set di chiavi pubbliche valide nel formato JWK Set a JWKSetURLs.
Esempio di KeyFunc personalizzata
La KeyFunc definisce una funzione definita dall'utente utilizzata per fornire chiavi pubbliche per la convalida del token. Questa funzione è responsabile della convalida dell'algoritmo di firma e della selezione della chiave corretta. Se il token è emesso da una parte esterna, la KeyFunc definita dall'utente può essere utile.
Quando viene fornita una KeyFunc definita dall'utente, le SigningKey, SigningKeys e SigningMethod verranno ignorati. Questa è una delle tre opzioni per fornire chiavi di convalida del token. L'ordine di priorità è la KeyFunc definita dall'utente, SigningKeys e SigningKey. Se né SigningKeys né SigningKey vengono forniti, questa funzione deve essere fornita. L'impostazione predefinita è convalidare l'algoritmo di firma e selezionare la chiave appropriata utilizzando l'implementazione interna.
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) {
// Controlla se il metodo di firma è corretto
if t.Method.Alg() != jwtware.HS256 {
return nil, fmt.Errorf("Metodo di firma jwt inaspettato=%v", t.Header["alg"])
}
// TODO Implementare il caricamento personalizzato della chiave di firma, ad esempio, caricare dal database
signingKey := "segreto"
return []byte(signingKey), nil
}
}