Fiber JWT
JWT 미들웨어는 JSON Web Token (JWT) 인증 미들웨어를 반환합니다. 유효한 토큰의 경우 사용자를 Ctx.Locals에 설정하고 다음 핸들러를 호출합니다. 유효하지 않은 토큰의 경우 "401 - Unauthorized" 오류를 반환하며, 누락된 토큰의 경우 "400 - Bad Request" 오류를 반환합니다.
참고: 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("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)
}
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"])
}
// TODO 서명 키의 사용자 정의 로딩 구현, 예를 들어 데이터베이스에서 로드
signingKey := "비밀키"
return []byte(signingKey), nil
}
}