Fiber JWT
Middleware JWT trả về một middleware xác thực JSON Web Token (JWT). Đối với một mã thông báo hợp lệ, nó đặt người dùng vào Ctx.Locals và gọi bộ xử lý tiếp theo. Đối với một mã thông báo không hợp lệ, nó trả về lỗi "401 - Unauthorized". Đối với một mã thông báo thiếu, nó trả về lỗi "400 - Bad Request".
Lưu ý: Yêu cầu phiên bản Go 1.19 trở lên
Cài đặt
Middleware này hỗ trợ Fiber v1 và v2, vui lòng cài đặt tương ứng.
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
Chữ ký
jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) error
Cấu hình
Thuộc tính | Kiểu | Mô tả | Giá trị mặc định |
---|---|---|---|
Filter | func(*fiber.Ctx) bool |
Xác định một hàm để bỏ qua middleware | nil |
SuccessHandler | func(*fiber.Ctx) error |
Xác định một hàm để thực thi khi có mã thông báo hợp lệ | nil |
ErrorHandler | func(*fiber.Ctx, error) error |
Xác định một hàm để thực thi khi có mã thông báo không hợp lệ | 401 Invalid or expired JWT |
SigningKey | interface{} |
Khóa ký được sử dụng để xác minh mã thông báo. Nếu độ dài của SigningKeys là 0, nó được sử dụng như một phương án dự phòng | nil |
SigningKeys | map[string]interface{} |
Ánh xạ của các khóa ký được sử dụng để xác minh mã thông báo với trường kid |
nil |
ContextKey | string |
Khóa ngữ cảnh được sử dụng để lưu thông tin người dùng từ mã thông báo trong ngữ cảnh | "user" |
Claims | jwt.Claim |
Dữ liệu yêu cầu mở rộng xác định nội dung của mã thông báo | jwt.MapClaims{} |
TokenLookup | string |
Một chuỗi theo định dạng : được sử dụng để phân tích mã thông báo |
"header:Authorization" |
AuthScheme | string |
AuthScheme được sử dụng trong tiêu đề Authorization. Giá trị mặc định ("Bearer") chỉ được sử dụng với giá trị TokenLookup mặc định |
"Bearer" |
KeyFunc | func() jwt.Keyfunc |
Một hàm do người dùng xác định để cung cấp khóa công khai cho xác minh mã thông báo | jwtKeyFunc |
JWKSetURLs | []string |
Một slice của các URL JSON Web Key (JWK) Set duy nhất được sử dụng để phân tích JWT | nil |
Ví dụ của 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()
// Tuyến đường đăng nhập
app.Post("/login", login)
// Tuyến đường có thể truy cập mà không cần xác thực
app.Get("/", accessible)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{Key: []byte("secret")},
}))
// Tuyến đường bị hạn chế
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Ném lỗi không được ủy quyền
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Tạo claims
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Tạo token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Tạo mã thông báo đã mã hóa và gửi như phản hồi
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)
}
Kiểm tra HS256
Đăng nhập bằng tên người dùng và mật khẩu để nhận một mã thông báo.
curl --data "user=john&pass=doe" http://localhost:3000/login
Phản hồi
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}
Sử dụng mã thông báo trong tiêu đề ủy quyền để yêu cầu tài nguyên bị hạn chế.
curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
Phản hồi
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 (
// Rõ ràng, đây chỉ là một ví dụ thử nghiệm. Đừng làm như vậy trong sản xuất.
// Trong sản xuất, bạn nên tạo cặp khóa trước.
// Không bao giờ thêm khóa riêng tư vào bất kỳ kho lưu trữ GitHub nào.
privateKey *rsa.PrivateKey
)
func main() {
app := fiber.New()
// Cho mục đích giới thiệu, tạo bộ khóa công khai / riêng tư mới mỗi khi chương trình chạy. Xem ghi chú ở trên.
rng := rand.Reader
var err error
privateKey, err = rsa.GenerateKey(rng, 2048)
if err != nil {
log.Fatalf("rsa.GenerateKey:%v", err)
}
// Route đăng nhập
app.Post("/login", login)
// Route không xác thực
app.Get("/", accessible)
// Middleware JWT
app.Use(jwtware.New(jwtware.Config{
SigningKey: jwtware.SigningKey{
JWTAlg: jwtware.RS256,
Key: privateKey.Public(),
},
}))
// Route bị hạn chế
app.Get("/restricted", restricted)
app.Listen(":3000")
}
func login(c *fiber.Ctx) error {
user := c.FormValue("user")
pass := c.FormValue("pass")
// Ném lỗi không cho phép
if user != "john" || pass != "doe" {
return c.SendStatus(fiber.StatusUnauthorized)
}
// Tạo các quyền
claims := jwt.MapClaims{
"name": "John Doe",
"admin": true,
"exp": time.Now().Add(time.Hour * 72).Unix(),
}
// Tạo mã thông báo
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
// Tạo mã thông báo đã mã hóa và gửi nó như là phản hồi
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("Welcome " + name)
}
Kiểm tra RS256
RS256 về cơ bản cũng giống như kiểm tra HS256 ở trên.
Kiểm tra JWK Set
Những kiểm tra này cũng giống như những kiểm tra JWT cơ bản ở trên, nhưng chúng yêu cầu bộ khóa công khai hợp lệ ở định dạng JWK Set tại JWKSetURLs.
Ví dụ về KeyFunc tùy chỉnh
KeyFunc định nghĩa một hàm do người dùng xác định được sử dụng để cung cấp các khóa công khai cho việc xác thực mã thông báo. Hàm này chịu trách nhiệm xác thực thuật toán chữ ký và lựa chọn đúng khóa. Nếu mã thông báo được phát hành bởi một bên thứ ba, thì KeyFunc do người dùng xác định có thể hữu ích.
Khi có KeyFunc do người dùng xác định, SigningKey, SigningKeys và SigningMethod sẽ bị bỏ qua. Điều này là một trong ba tùy chọn để cung cấp các khóa xác thực mã thông báo. Thứ tự ưu tiên là KeyFunc do người dùng xác định, SigningKeys và SigningKey. Nếu cả SigningKeys và SigningKey đều không được cung cấp, thì hàm này phải được cung cấp. Mặc định là xác thực thuật toán chữ ký và lựa chọn khóa thích hợp bằng cách sử dụng triển khai nội bộ.
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) {
// Kiểm tra xem phương thức chữ ký có đúng không
if t.Method.Alg() != jwtware.HS256 {
return nil, fmt.Errorf("Phương thức ký jwt không mong đợi=%v", t.Header["alg"])
}
// TODO Thực hiện tải khóa ký tùy chỉnh, ví dụ, tải từ cơ sở dữ liệu
signingKey := "mật khẩu"
return []byte(signingKey), nil
}
}