Fiber JWT
Le middleware JWT renvoie un middleware d'authentification JSON Web Token (JWT). Pour un jeton valide, il définit l'utilisateur dans Ctx.Locals et appelle le gestionnaire suivant. Pour un jeton invalide, il renvoie une erreur "401 - Non autorisé". Pour un jeton manquant, il renvoie une erreur "400 - Requête incorrecte".
Remarque : la version de Go 1.19 ou supérieure est requise
Installation
Ce middleware prend en charge Fiber v1 et v2, veuillez installer en conséquence.
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
Signature
jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) error
Configuration
Propriété | Type | Description | Valeur par défaut |
---|---|---|---|
Filter | func(*fiber.Ctx) bool |
Définit une fonction pour sauter le middleware | nil |
SuccessHandler | func(*fiber.Ctx) error |
Définit une fonction à exécuter lors d'un jeton valide | nil |
ErrorHandler | func(*fiber.Ctx, error) error |
Définit une fonction à exécuter lors d'un jeton invalide | 401 JWT invalide ou expiré |
SigningKey | interface{} |
La clé de signature utilisée pour vérifier le jeton. Si la longueur de SigningKeys est de 0, elle est utilisée comme solution de secours | nil |
SigningKeys | map[string]interface{} |
La correspondance des clés de signature utilisées pour vérifier les jetons avec un champ kid |
nil |
ContextKey | string |
La clé de contexte utilisée pour stocker les informations d'utilisateur du jeton dans le contexte | "utilisateur" |
Claims | jwt.Claim |
Les données de revendications étendues définissant le contenu du jeton | jwt.MapClaims{} |
TokenLookup | string |
Une chaîne au format : utilisée pour analyser le jeton |
"header:Authorization" |
AuthScheme | string |
Le schéma d'authentification utilisé dans l'en-tête Authorization. La valeur par défaut ("Bearer") est utilisée uniquement avec la valeur TokenLookup par défaut |
"Bearer" |
KeyFunc | func() jwt.Keyfunc |
Une fonction définie par l'utilisateur pour fournir une clé publique pour la vérification du jeton | jwtKeyFunc |
JWKSetURLs | []string |
Une liste d'URL de jeu de clés JSON Web (JWK) uniques utilisée pour analyser les JWT | nil |
Exemple de 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()
// Route de connexion
app.Post("/login", login)
// Route accessible sans authentification
app.Get("/", accessible)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{Clé: []byte("secret")},
}))
// Route restreinte
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
utilisateur := c.FormValue("utilisateur")
pass := c.FormValue("pass")
// Envoi d'une erreur non autorisée
if utilisateur != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Création de revendications
claims := jwt.MapClaims{
"nom": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Création du jeton
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Génération du jeton encodé et envoi en réponse
t, err := token.SignedString([]byte("secret"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(fiber.Map{"jeton": t})
}
func accessible(c *fiber.Ctx) error {
return c.SendString("Accessible")
}
func restricted(c *fiber.Ctx) error {
utilisateur := c.Locals("utilisateur").(*jwt.Token)
claims := utilisateur.Claims.(jwt.MapClaims)
nom := claims["nom"].(string)
return c.SendString("Bienvenue " + nom)
}
Test HS256
Connectez-vous avec un nom d'utilisateur et un mot de passe pour obtenir un jeton.
curl --data "user=john&pass=doe" http://localhost:3000/login
Réponse
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}
Demander l'accès restreint en utilisant le jeton dans l'en-tête d'autorisation.
curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
Réponse
Bienvenue 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 (
// De toute évidence, ceci n'est qu'un exemple de test. Ne le faites pas en production.
// En production, vous devriez générer la paire de clés au préalable.
// N'ajoutez jamais la clé privée à un dépôt GitHub.
privateKey *rsa.PrivateKey
)
func main() {
app := fiber.New()
// Pour la démonstration, générez une nouvelle paire de clés privée/publique à chaque exécution du programme. Voir la note ci-dessus.
rng := rand.Reader
var err error
privateKey, err = rsa.GenerateKey(rng, 2048)
if err != nil {
log.Fatalf("rsa.GenerateKey:%v", err)
}
// Route de connexion
app.Post("/login", login)
// Route non authentifiée
app.Get("/", accessible)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{
JWTAlg: jwtware.RS256,
Key: privateKey.Public(),
},
}))
// Route restreinte
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Renvoyer une erreur non autorisée
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Créer des revendications
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Créer un jeton
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
// Générer un jeton encodé et l'envoyer comme réponse
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("Bienvenue " + name)
}
Test RS256
RS256 est essentiellement identique au test HS256 ci-dessus.
Test de l'ensemble JWK
Ces tests sont identiques aux tests JWT de base ci-dessus, mais ils nécessitent des ensembles de clés publiques valides au format JWK Set à JWKSetURLs.
Exemple de Custom KeyFunc
La fonction KeyFunc définit une fonction définie par l'utilisateur utilisée pour fournir des clés publiques pour la validation de jetons. Cette fonction est responsable de la validation de l'algorithme de signature et de la sélection de la clé appropriée. Si le jeton est émis par une partie externe, la KeyFunc définie par l'utilisateur peut être utile.
Lorsqu'une KeyFunc définie par l'utilisateur est fournie, SigningKey, SigningKeys et SigningMethod seront ignorés. Il s'agit de l'une des trois options pour fournir des clés de validation de jetons. L'ordre de priorité est le suivant : KeyFunc définie par l'utilisateur, SigningKeys et SigningKey. Si ni SigningKeys ni SigningKey ne sont fournis, cette fonction doit être fournie. Par défaut, la validation de l'algorithme de signature et la sélection de la clé appropriée se font à l'aide de l'implémentation interne.
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) {
// Vérifier si la méthode de signature est correcte
if t.Method.Alg() != jwtware.HS256 {
return nil, fmt.Errorf("Méthode de signature jwt inattendue = %v", t.Header["alg"])
}
// TODO Implémenter le chargement personnalisé de la clé de signature, par exemple, charger depuis la base de données
signingKey := "secret"
return []byte(signingKey), nil
}
}