golang-jwt 의 SignedString, Parse 함수 코드 분석

Sammy·2024년 4월 18일
0

Authorization

목록 보기
3/9

SignedString

func (t *Token) SignedString(key interface{}) (string, error) {
   sstr, err := t.SigningString()
   if err != nil {
      return "", err
   }
   sig, err := t.Method.Sign(sstr, key)
   if err != nil {
      return "", err
   }
   return sstr + "." + t.EncodeSegment(sig), nil
}
  1. 토큰의 Header 와 Claim 을 마샬링한다.
  2. 마샬링한 Header와 Claim 을 base64로 인코딩해서 base64EncodedHeader.base64EncodedClaim 형태의 string 값을 만든다.
  3. 지정한 해시 알고리즘과 secret key 로 HMAC 해시 함수를 생성한다.
  4. 2번에서 만들어진 문자열에 대해 HMAC 해시 함수를 적용하여 signature 을 생성한다.
  5. 2번문자열. 뒤에 base64로 인코딩된 signature 을 결합하여 해당 문자열을 반환한다.

ParseWithClaims

func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
	token, parts, err := p.ParseUnverified(tokenString, claims)
	if err != nil {
		return token, err
	}
	// Verify signing method is in the required set
	if p.validMethods != nil {
		var signingMethodValid = false
		var alg = token.Method.Alg()
		for _, m := range p.validMethods {
			if m == alg {
				signingMethodValid = true
				break
			}
		}
		if !signingMethodValid {
			// signing method is not in the listed set
			return token, newError(fmt.Sprintf("signing method %v is invalid", alg), ErrTokenSignatureInvalid)
		}
	}
	// Decode signature
	token.Signature, err = p.DecodeSegment(parts[2])
	if err != nil {
		return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
	}
	text := strings.Join(parts[0:2], ".")
	// Lookup key(s)
	if keyFunc == nil {
		// keyFunc was not provided.  short circuiting validation
		return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
	}
	got, err := keyFunc(token)
	if err != nil {
		return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
	}
	switch have := got.(type) {
	case VerificationKeySet:
		if len(have.Keys) == 0 {
			return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
		}
		// Iterate through keys and verify signature, skipping the rest when a match is found.
		// Return the last error if no match is found.
		for _, key := range have.Keys {
			if err = token.Method.Verify(text, token.Signature, key); err == nil {
				break
			}
		}
	default:
		err = token.Method.Verify(text, token.Signature, have)
	}
	if err != nil {
		return token, newError("", ErrTokenSignatureInvalid, err)
	}
	// Validate Claims
	if !p.skipClaimsValidation {
		// Make sure we have at least a default validator
		if p.validator == nil {
			p.validator = NewValidator()
		}
		if err := p.validator.Validate(claims); err != nil {
			return token, newError("", ErrTokenInvalidClaims, err)
		}
	}
	// No errors so far, token is valid.
	token.Valid = true
	return token, nil
}
  1. tokenString 의 Header와 Claims 을 parsing 한다.
  2. tokenString 의 Signature 를 Decode 한다.
  3. Header의 해시 알고리즘과 Secret Key 로 HMAC 해시 함수를 생성한다.
  4. Header와 Payload 까지 만들어진 string 값에 HMAC 해시 함수를 적용한다.
  5. 기존 signature 값과 동일한지 검증한다.
  6. 토큰 등록된 클레임값을 검증한다.
  7. 모두 통과되면 token.Valid 값을 true 로 바꾸어 반환한다.
profile
Web Developer

0개의 댓글