-
[golang] JWT 활용하기카테고리 없음 2020. 10. 7. 22:28
JWT란?
JWT는 JSON Web Token의 약자로, 특정 환경에 있는 사용자의 권한 요청이나 데이터를 안전하게 전달하는 표준이다. 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 }