Fiber JWT

JWT ミドルウェアは、JSON Web Token (JWT) 認証ミドルウェアを返します。有効なトークンの場合、ユーザーを Ctx.Locals に設定し、次のハンドラーを呼び出します。無効なトークンの場合は、「401 - 認証されていません」エラーを返します。トークンが不足している場合は、「400 - リクエストが不正です」エラーを返します。

注: Go バージョン 1.19 以上が必要です

インストール

このミドルウェアは Fiber v1 および v2 をサポートしています。それぞれに合わせてインストールしてください。

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

シグネチャ

jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) error

設定

プロパティ タイプ 説明 デフォルト値
Filter func(*fiber.Ctx) bool ミドルウェアをスキップするための関数 nil
SuccessHandler func(*fiber.Ctx) error 有効なトークンがある場合に実行する関数 nil
ErrorHandler func(*fiber.Ctx, error) error 無効なトークンがある場合に実行する関数 401 Invalid or expired JWT
SigningKey interface{} トークンを検証するために使用される署名キー。SigningKeys の長さが 0 の場合はフォールバックとして使用されます nil
SigningKeys map[string]interface{} kid フィールドを持つトークンを検証するために使用される署名キーのマッピング nil
ContextKey string コンテキスト内のトークンからユーザー情報を格納するために使用されるコンテキストキー "user"
Claims jwt.Claim トークン内容を定義する拡張クレームデータ jwt.MapClaims{}
TokenLookup string トークンを解析するために使用されるフォーマット : を含む文字列 "header:Authorization"
AuthScheme string Authorization ヘッダーで使用される AuthScheme。デフォルト値 ("Bearer") はデフォルトの TokenLookup 値と一緒に使用されます "Bearer"
KeyFunc func() jwt.Keyfunc トークンの検証のために公開鍵を提供するユーザー定義関数 jwtKeyFunc
JWKSetURLs []string JWT の解析に使用される一意の JSON Web Key (JWK) Set URL のスライス nil

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()

	// ログインルート
	app.Post("/login", login)

	// 認証なしでアクセス可能なルート
	app.Get("/", accessible)

	// JWT ミドルウェア
	app.Use(jwtware.New(jwtware.Config{
		SigningKey: jwtware.SigningKey{Key: []byte("secret")},
	}))

	// 制限付きルート
	app.Get("/restricted", restricted)

	app.Listen(":3000")
}

func login(c *fiber.Ctx) error {
	user := c.FormValue("user")
	pass := c.FormValue("pass")

	// 認証エラーをスロー
	if user != "john" || pass != "doe" {
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	// クレームを作成
	claims := jwt.MapClaims{
		"name":  "John Doe",
		"admin": true,
		"exp":   time.Now().Add(time.Hour * 72).Unix(),
	}

	// トークンを作成
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// エンコードされたトークンを生成してレスポンスとして送信
	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("アクセス可能")
}

func restricted(c *fiber.Ctx) error {
	user := c.Locals("user").(*jwt.Token)
	claims := user.Claims.(jwt.MapClaims)
	name := claims["name"].(string)
	return c.SendString("ようこそ " + name + " さん")
}

HS256 テスト

ユーザー名とパスワードでログインしてトークンを取得します。

curl --data "user=john&pass=doe" http://localhost:3000/login

レスポンス

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}

認証ヘッダー内のトークンを使用してリクエストを制限されたリソースに送信します。

curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"

レスポンス

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 (
	// 明らかに、これは単なるテストの例です。本番環境では行わないでください。
	// 本番環境では、事前にキーペアを生成する必要があります。
	// 私鍵を GitHub リポジトリに追加しないでください。
	privateKey *rsa.PrivateKey
)

func main() {
	app := fiber.New()

	// デモ用に、プログラムが実行されるたびに新しい秘密鍵/公開鍵ペアを生成します。上記の注釈を参照してください。
	rng := rand.Reader
	var err error
	privateKey, err = rsa.GenerateKey(rng, 2048)
	if err != nil {
		log.Fatalf("rsa.GenerateKey:%v", err)
	}

	// ログインルート
	app.Post("/login", login)

	// 認証なしのルート
	app.Get("/", accessible)

	// JWT ミドルウェア
	app.Use(jwtware.New(jwtware.Config{
		SigningKey: jwtware.SigningKey{
			JWTAlg: jwtware.RS256,
			Key:    privateKey.Public(),
		},
	}))

	// 制限されたルート
	app.Get("/restricted", restricted)

	app.Listen(":3000")
}

func login(c *fiber.Ctx) error {
	user := c.FormValue("user")
	pass := c.FormValue("pass")

	// 認証エラーをスロー
	if user != "john" || pass != "doe" {
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	// クレームを作成
	claims := jwt.MapClaims{
		"name":  "John Doe",
		"admin": true,
		"exp":   time.Now().Add(time.Hour * 72).Unix(),
	}

	// トークンを作成
	token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)

	// エンコードされたトークンを生成してレスポンスとして送信します
	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)
}

RS256 テスト

RS256 は上記の HS256 テストと本質的に同じです。

JWK セット テスト

これらのテストは基本の JWT テストと同じですが、JWK Set 形式の有効な公開鍵セットが JWKSetURLs に必要です。

カスタム KeyFunc の例

KeyFunc は、トークンの検証に使用されるユーザー定義の関数を定義します。この関数は、署名アルゴリズムの検証および正しいキーの選択に責任を持ちます。もしトークンが外部のパーティによって発行された場合、ユーザー定義の KeyFunc が役立つかもしれません。

ユーザー定義の KeyFunc が提供されると、SigningKey、SigningKeys、および SigningMethod は無視されます。これはトークン検証キーを提供するための三つのオプションのうちの一つです。優先順位は、ユーザー定義の KeyFunc、SigningKeys、SigningKey の順です。SigningKeys と SigningKey の両方が提供されない場合、この関数は必ず提供されなければなりません。デフォルトでは、内部実装を使用して署名アルゴリズムを検証し、適切なキーを選択します。

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) {
		// 署名メソッドが正しいかどうかを確認
		if t.Method.Alg() != jwtware.HS256 {
			return nil, fmt.Errorf("予期しない jwt 署名メソッド=%v", t.Header["alg"])
		}

		// 署名キーのカスタム読み込みを実装する、たとえば、データベースから読み込む
    signingKey := "secret"

		return []byte(signingKey), nil
	}
}