JWT Authorization

Sammy·2024년 4월 18일
0

Authorization

목록 보기
1/9

JWT Authorization

  • 사용자를 인증하고 식별하기 위한 정보들을 암호화 시킨 토큰
  • JSON 데이터를 base64로 인코딩하여 직렬화하는 방식
  • 쿠키를 통해 클라이언트(로컬 스토리지)에 저장
  • HTTP 요청 시 헤더에 토큰을 첨부하는 것 만으로 데이터를 요청하고 응답을 받을 수 있음
  • . 을 기준으로 Header, Payload, Signature 로 나누어져 있음

  • Header: 토큰의 타입과 알고리즘
  • Payload: 토큰에 담을 클레임 정보
    • 등록된 클레임: 이름이 이미 정해져 있는 클레임 (e.g. exp, iss, sub)
    • 공개 클레임: 충돌 방지를 위해 URI 형태로 이름을 짓는 클레임
    • 비공개 클레임: 클라이언트와 서버간 협의하에 사용되는 클레임
  • Signature
    • secret key 를 포함하여 암호화
    • 공격자가 JWT 내부 값은 변경해도 signature로 유효하지 않다는 걸 인식할 수 있다.

Claim

JWT에서 "클레임(Claim)"이라는 용어를 사용하는 이유는 토큰의 Payload에 포함된 정보가 특정한 주장(claim)을 나타내기 때문입니다. 이러한 클레임은 토큰을 발행하는 측이나 토큰을 사용하는 측에게 특정한 정보나 상태를 알려주는 역할을 합니다.

예를 들어, JWT의 클레임으로는 토큰의 발급자, 토큰의 주제, 토큰의 만료 시간 등이 있습니다. 이러한 정보들은 토큰을 검증하는 측에게 중요한 정보를 제공하며, 이를 통해 토큰의 유효성을 확인하고 필요한 권한을 부여할 수 있습니다.

따라서 클레임이라는 용어는 JWT가 담고 있는 정보가 단순히 데이터일 뿐만 아니라, 해당 정보가 특정한 정보나 상태를 나타낸다는 의미를 강조하기 위해 사용됩니다. 이는 JWT가 인증과 권한 관리 등의 목적으로 사용되는 보안 토큰이기 때문에 중요한 개념입니다.

코드 예시

package main
import (
	"fmt"
	"net/http"
	"time"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)
func main() {
	router := gin.Default()
	router.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "Hello, World!")
	})
	router.POST("/log-in", LogInHandler)
	router.GET("/verify", VerifyHandler)
	router.Run(":8080")
}
type LogInRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}
func LogInHandler(c *gin.Context) {
	var req *LogInRequest
	err := c.ShouldBindJSON(&req)
	if err != nil {
		c.String(http.StatusBadRequest, "Invalid request")
		return
	}
	if req.Username != "semyeong" || req.Password != "1234" {
		c.String(http.StatusUnauthorized, "Incorrect username or password")
		return
	}
	token, err := CreateToken(req.Username)
	if err != nil {
		c.String(http.StatusInternalServerError, "CreateToken error")
		return
	}
	c.String(http.StatusOK, token)
}
func VerifyHandler(c *gin.Context) {
	tokenString := c.GetHeader("Authorization")
	if tokenString == "" {
		c.String(http.StatusUnauthorized, "Missing authorization header")
		return
	}
	tokenString = tokenString[len("Bearer "):]
	err := VerifyToken(tokenString)
	if err != nil {
		c.String(http.StatusUnauthorized, "Invalid Token")
		return
	}
	c.String(http.StatusOK, "Valid Token!")
}
var secretKey = []byte("secret-key")
func CreateToken(username string) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256,
		jwt.MapClaims{
			"username": username,
			"exp":      time.Now().Add(time.Hour * 24).Unix(),
		})
	tokenString, err := token.SignedString(secretKey)
	if err != nil {
		return "", err
	}
	return tokenString, nil
}
func VerifyToken(tokenString string) error {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return secretKey, nil
	})
	if err != nil {
		return err
	}
	if !token.Valid {
		return fmt.Errorf("invalid token")
	}
	return nil
}
profile
Web Developer

0개의 댓글