JWT
JWT는 JSON Web Token(JWT) 인증 미들웨어를 반환합니다. 유효한 토큰의 경우 Ctx.Locals에 사용자를 설정하고 다음 핸들러를 호출합니다. 유효하지 않은 토큰의 경우 "401 - Unauthorized" 오류를 반환합니다. 토큰이 누락된 경우 "400 - Bad Request" 오류를 반환합니다.
Echo에 특별한 감사와 크레딧을 드립니다.
참고: Go 1.19 이상 버전 필요
Installation
이 미들웨어는 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/v5Signatures
jwtware.New(config ...jwtware.Config) func(*fiber.Ctx) errorConfig
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
<source>:<name> 형식의 문자열로 사용
"header:Authorization"
AuthScheme
string
Authorization 헤더에 사용할 인증 스킴. 기본값("Bearer")은 기본 TokenLookup 값과 함께 사용될 때만 사용
"Bearer"
KeyFunc
func() jwt.Keyfunc
토큰 검증을 위한 공개 키를 제공하는 사용자 정의 함수
jwtKeyFunc
JWKSetURLs
[]string
JWT를 파싱하는 데 사용되는 고유한 JSON Web Key(JWK) 세트 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"
}Authorization 요청 헤더의 토큰을 사용하여 제한된 리소스를 요청합니다.
curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY" 응답
Welcome John DoeRS256 예제
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 테스트와 동일하지만, RFC 7517에 명시된 JSON Web Key(JWK) 세트 형식의 유효한 공개 키 컬렉션에 대한 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("Unexpected jwt signing method=%v", t.Header["alg"])
}
// TODO 데이터베이스 등에서 서명 키를 로드하는 사용자 정의 구현
signingKey := "secret"
return []byte(signingKey), nil
}
}Last updated