JWT do Fiber
O middleware JWT retorna um middleware de autenticação de Token de Web JSON (JWT). Para um token válido, ele define o usuário em Ctx.Locals e chama o próximo manipulador. Para um token inválido, retorna um erro "401 - Não Autorizado". Para um token ausente, retorna um erro "400 - Solicitação Inválida".
Observação: É necessário o Go na versão 1.19 ou superior
Instalação
Este middleware suporta Fiber v1 e v2, por favor, instale de acordo com a versão.
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
Assinatura
jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) error
Configuração
Propriedade | Tipo | Descrição | Valor Padrão |
---|---|---|---|
Filtro | func(*fiber.Ctx) bool |
Define uma função para pular o middleware | nil |
Manipulador de Sucesso | func(*fiber.Ctx) error |
Define uma função a ser executada ao validar o token | nil |
Manipulador de Erro | func(*fiber.Ctx, error) error |
Define uma função a ser executada ao validar o token como inválido | 401 Token JWT inválido ou expirado |
Chave de Assinatura | interface{} |
A chave de assinatura usada para verificar o token. Se o comprimento de SigningKeys for 0, é usada como alternativa | nil |
Chaves de Assinatura | map[string]interface{} |
O mapeamento de chaves de assinatura usadas para verificar tokens com um campo kid |
nil |
Chave de Contexto | string |
A chave de contexto usada para armazenar informações do usuário do token no contexto | "user" |
Reivindicações | jwt.Claim |
Os dados de reivindicações estendidas que definem o conteúdo do token | jwt.MapClaims{} |
TokenLookup | string |
Uma string no formato : usada para analisar o token |
"header:Authorization" |
Esquema de Autenticação | string |
O esquema de autenticação usado no cabeçalho Autorização. O valor padrão ("Bearer") é usado apenas com o valor padrão TokenLookup |
"Bearer" |
KeyFunc | func() jwt.Keyfunc |
Uma função definida pelo usuário para fornecer chave pública para verificação de token | jwtKeyFunc |
JWKSetURLs | []string |
Uma lista de URLs de Conjunto de Chave Web JSON (JWK) exclusivas utilizadas para analisar JWT | nil |
Exemplo 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()
// Rota de login
app.Post("/login", login)
// Rota acessível sem autenticação
app.Get("/", acessivel)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
ChaveDeAssinatura: jwtware.SigningKey{Key: []byte("secret")},
}))
// Rota restrita
app.Get("/restrito", restrito)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
usuário := c.FormValue("usuário")
senha := c.FormValue("senha")
// Lançando erro não autorizado
if usuário != "john" || senha != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Criando reivindicações
reivindicações := jwt.MapClaims{
"nome": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Criando token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, reivindicações)
// Gerando token codificado e enviando como resposta
t, err := token.SignedString([]byte("secret"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(fiber.Map{"token": t})
}
func acessivel(c *fiber.Ctx) error {
return c.SendString("Acessível")
}
func restrito(c *fiber.Ctx) error {
usuário := c.Locals("user").(*jwt.Token)
reivindicações := usuário.Claims.(jwt.MapClaims)
nome := reivindicações["nome"].(string)
return c.SendString("Bem-vindo " + nome)
}
Teste HS256
Faça login com nome de usuário e senha para obter um token.
curl --data "user=john&pass=doe" http://localhost:3000/login
Resposta
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}
Solicitar recurso restrito usando o token no cabeçalho de autorização.
curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
Resposta
Bem-vindo 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 (
// Obviamente, este é apenas um exemplo de teste. Não faça isso em produção.
// Em produção, você deve gerar o par de chaves antecipadamente.
// Nunca adicione a chave privada a nenhum repositório do GitHub.
privateKey *rsa.PrivateKey
)
func main() {
app := fiber.New()
// Para demonstração, gere um novo par de chaves público/privado cada vez que o programa é executado. Veja a observação acima.
rng := rand.Reader
var err error
privateKey, err = rsa.GenerateKey(rng, 2048)
if err != nil {
log.Fatalf("rsa.GenerateKey:%v", err)
}
// Rota de login
app.Post("/login", login)
// Rota não autenticada
app.Get("/", acessível)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{
JWTAlg: jwtware.RS256,
Key: privateKey.Público(),
},
}))
// Rota restrita
app.Get("/restricted", restrito)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Lançar erro não autorizado
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Criar reivindicações
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Criar token
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
// Gerar token codificado e enviá-lo como resposta
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("Acessível")
}
func restricted(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["name"].(string)
return c.SendString("Bem-vindo " + name)
}
Teste RS256
O RS256 é essencialmente o mesmo que o teste HS256 acima.
Teste de Conjunto JWK
Esses testes são os mesmos que os testes básicos de JWT acima, mas exigem conjuntos de chaves públicas válidas no formato de Conjunto JWK em JWKSetURLs.
Exemplo de Custom KeyFunc
O KeyFunc define uma função definida pelo usuário usada para fornecer chaves públicas para validação do token. Esta função é responsável por validar o algoritmo de assinatura e selecionar a chave correta. Se o token for emitido por uma parte externa, o KeyFunc definido pelo usuário pode ser útil.
Quando um KeyFunc definido pelo usuário é fornecido, o SigningKey, SigningKeys e SigningMethod serão ignorados. Esta é uma das três opções para fornecer chaves de validação de token. A ordem de prioridade é KeyFunc definido pelo usuário, SigningKeys e SigningKey. Se nenhum SigningKeys nem SigningKey for fornecido, esta função deve ser fornecida. O padrão é validar o algoritmo de assinatura e selecionar a chave apropriada usando a implementação 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) {
// Verifica se o método de assinatura está correto
if t.Method.Alg() != jwtware.HS256 {
return nil, fmt.Errorf("Método de assinatura inesperado=%v", t.Header["alg"])
}
// TODO Implementar o carregamento personalizado da chave de assinatura, por exemplo, carregar do banco de dados
signingKey := "secreto"
return []byte(signingKey), nil
}
}