본문 바로가기
Programming/Go

[GO 인증 구현 with JWT 3] 인증 미들웨어 구현 및 테스트 코드 작성

by TinKerBellBass 2022. 4. 11.
728x90
반응형

이전 글

 

[GO 인증 구현 with JWT 1] 전체적인 인터페이스 작성

Use Case 간단히 구현해 볼 인증의 시나리오 유저 생성 → 생성된 유저 정보로 토큰 발급 → 발급된 토큰에 들어있는 유저ID 를 이용해서 유저 정보 획득 유저 생성 Use Case User ID, Password 를 입력받아

tinkerbellbass.tistory.com

 

토큰을 만들고 검증할 수 있게 되었으니 다음으로 인증 미들웨어를 구현해 보자.

 

인증 미들웨어 구현

리퀘스트 헤더에서 토큰 값을 가져오는 getTokenFromRequest 메서드부터 구현해 보자.

인증 방식이 Basic 이 아닌 Bearer 인지 확인한 후 토큰을 가져오는 메서드로,

인증 방식 스킴은 대소문자 구분이 없으므로 인증 방식 스킴 비교 시에는 대문자로 통일해서 검증하며,

헤더 값에서 스킴은 빼고 토큰 값만 반환한다.

const (
	BearerSchema string = "BEARER "
)

func getTokenFromRequest(r *http.Request) (string, error) {
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		return "", errors.New(authentication.ErrAuthorizationHeaderRequired)
	}

	bearerLength := len(BearerSchema)
	if len(authHeader) > bearerLength && strings.ToUpper(authHeader[0:bearerLength]) == BearerSchema {
		return authHeader[bearerLength:], nil
	}

	return "", errors.New(authentication.ErrInvalidBearerScheme)
}

 

다음으로 인증 미들웨어 함수를 만들어 반환하는 AuthenticateMiddleware 메서드를 구현해 보자.

인증 미들웨어를 반환하는 부분은 Authentication 구조체를 만들어서 구조체의 함수로 변경하였다.

리퀘스트 헤더에서 토큰 가져와서 검증하고, 검증이 통과되면 context 에 저장하고

다음 http Handler 에게 넘겨준다. 요청 전 단계에서 사용되는 스프링의 인터셉터 같은 느낌이다.

type Authentication struct {
	secret string
}

func (a *Authentication) AuthenticateMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token, err := getTokenFromRequest(r)
		if err != nil {
			http.Error(w, err.Error(), authentication.ErrStatusCode(err))
			return
		}

		userID, err := ValidateToken(token, a.secret)
		if err != nil {
			http.Error(w, err.Error(), authentication.ErrStatusCode(err))
			return
		}

		ctx := context.WithValue(r.Context(), "user_id", userID)

		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

 

테스트 코드 작성 

어떻게 해도 테스트 하기 힘든 코드는 생산되기 때문에

100% 테스트 커버리지는 신의 영역이라 생각한다.

 

인증 미들웨어를 반환하는 AuthenticateMiddleware 를 테스트하는 방법 중 하나로

반환되는 함수를 실행시켜 테스트해보는 것이다.

먼저 성공 케이스를 생각해 보면

context 에 User ID 값이 제대로 설정되었나 검증해 볼 수 있을 것이다.

문제는 메서드 안에서 context 가 생성되어 next.ServerHTTP 메서드의 인자 값으로 들어간다.

그러면 next.ServerHTTP 가 실행될 때의 리퀘스트 값에서 context 를 뽑아서 테스트해봐야 하는데

가능할 것 같지 않다.

 

방법으로는 가짜 목 서버 띄우고 하면 되겠지만 이럴 경우 보통 단위 테스트를 포기하고

통합 테스트에서 실제로 시나리오를 세워서 테스트 해보는게 더 좋은 것 같다.

테스트 작성이 실제 로직 구현보다 빡시다면 그건 잘못되었다고 생각한다.

 

물론 아무리 힘들어도 테스트는 빡시고 처절하게 테스트 커버리지 100%를 지향해야 한다는 것도 맞다.

세상을 흑백으로 구분할 필요는 없으니까 각자 알아서 판단하고 프로젝트 성향에 맞춰서 판단하면 될 것 같다.

 

이제 리포지토리, 서비스, 핸들러 구현과 메인 함수 구현만 남았다. 하나씩 하나씩 기능을 완성해 가자.

전체 소스는 https://github.com/jongwon-hyun/go_auth_jwt

 

다음 글

 

[GO 인증 구현 with JWT 4] User Repository, Service 구현 및 테스트

이전 글 [GO 인증 구현 with JWT 3] 인증 미들웨어 구현 및 테스트 코드 작성 이전 글 [GO 인증 구현 with JWT 1] 전체적인 인터페이스 작성 Use Case 간단히 구현해 볼 인증의 시나리오 유저 생성 → 생성된

tinkerbellbass.tistory.com

 

728x90
반응형

댓글