ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [golang] JWT 활용하기
    카테고리 없음 2020. 10. 7. 22:28

    JWT란?

    JWT는 JSON Web Token의 약자로, 특정 환경에 있는 사용자의 권한 요청이나 데이터를 안전하게 전달하는 표준이다.  JWT에는 두 가지 주요 장점이 있는데, 하나는 여러 프레임워크에서 사용할 수 있다는 점이고, 또 다른 하나는 비대칭 암호화를 사용한다는 점이다. 즉, 토큰이 서명돼 있으므로 서명자의 공개 키만 있으면 수신자는 토큰이 실제로 신뢰할 수 있는 출처에서 왔는지 확인할 수 있으며, 이를 통해 인증 서버의 개인 키에 대한 불필요한 접근을 막을 수 있다.

     

    JWT의 형식

    JWT 구조

    JWT 토큰은 URI에서 파라미터로 사용할 수 있도록 URL-Safe한('+','=','/' 등의 기호를 특정 문자로 대체하고, 패딩을 제거한 후 base64로 암호화시킴) Base64url 인코딩을 사용한다. 

     

     헤더(Haeder)에는 토큰의 타입과 해시 알고리즘을 나타내는 정보가 들어있고

     페이로드(Payload)에는 토큰에 담을 정보가 들어있다. 여기에 담는 정보의 한 ‘조각’ 을 클레임(Claim) 이라고 부르고, 이는 Json(Key/Value) 형태의 한 쌍으로 이루어져있다. 클레임 의 종류는 아래과 같이 크게 세 분류로 나뉘어져있다:

    • 등록된 (registered) 클레임
    • 공개 (public) 클레임
    • 비공개 (private) 클레임

    1) 등록된 클레임(Registered Claim)

    • 등록된 클레임들은 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임이다. 등록된 클레임의 사용은 모두 선택적 (optional)이며, 이에 포함된 클레임 이름들은 다음과 같다.
      • iss : 토큰 발급자 (issuer)
      • sub : 토큰 제목 (subject)
      • aud : 토큰 대상자 (audience)
      • exp : 토큰의 만료시간 (expiraton)
      • nbf : Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념이며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않는다.
      • iat : 토큰이 발급된 시간 (issued at)
      • jti : JWT의 고유 식별자

    예시

    { 
      "iss": "strange-developer.tistory.com", 
      "exp": "1602076408", 
      "https://strange-developer.tistory.com/jwt_claims/is_admin": true, 
      "userId": "strangedeveloper", 
      "username": "min" 
    }

    => 참고로 위의 예시는 2개의 Registered Claim, 1개의 Public Claim, 2개의 Private Claim으로 이루어져있다.

     

    2) 공개 클레임(Public Claim)

    • 공개 클레임들은 충돌이 방지된 (collision-resistant) 이름을 가지고 있어야 하며, 충돌을 방지하기 위해서는 클레임 이름을 URI 형식으로 짓는다.
    {
      "strange-developer.com/jwt_claims/is_admin": true 
    }

     

    3) 비공개 클레임(Private Claim)

    • 클라이언트와 서버가 협의하에 클레임을 지정해서 사용
    { 
      "userId": "strangedeveloper" 
    }

     

    Go로 구현하기

    1) JWT 생성

    func GenerateJWT() []byte {
        // 클레임 생성
    	claims := jws.Claims{}
        // 만료일 2주로 설정
    	claims.SetExpiration(time.Now().Add(2880 * time.Minute))
        // 클레임 목록 설정
    	claims.Set("userId", "strangedeveloper")
    
    	// 새로운 JWT를 만듦
    	jwt := jws.NewJWT(claims, crypto.SigningMethodRS256)
    
    	// 개인키를 받아서 인코딩된 형식의 바이트 슬라이스를 리턴받음.
    	b, _ := jwt.Serialize(rsaPrivate)
    
    	return b
    }

     

    2) 검증

    func ValidateJWT(token []byte) error {
        // 바이트로 된 JWT를 파싱
    	jwt, err := jws.ParseJWT(token)
    	if err != nil {
    		return fmt.Errorf("Unable to parse token: %v", err)
    	}
    
        // 메세지에 서명한 비공개 키와 관련된 공개 키 및 서명에 사용한 메서드를 받아서 유효성 검증
    	if err = jwt.Validate(rsaPublic, crypto.SigningMethodRS256); err != nil {
    		return fmt.Errorf("Unable to validate token: %v", err)
    	}
    
    	return nil
    }
Designed by Tistory.