Kotlin으로 카카오 로그인 구현하기-2

문지은·2021년 10월 18일
0
post-thumbnail

저번에 jwt 관련 세팅을 완료했다. 이제 거의 다 왔다!

회원 가입, 로그인 플로우

이제 회원 가입과 로그인의 플로우를 좀 더 구체화해보자.

회원 가입
1. 카카오 access token을 포함한 회원 가입에 필요한 정보를 코틀린 서버에 전송
2. 카카오 access token의 유효성 검증
3. 이미 가입한 회원이면 에러 리턴
4. DB에 사용자 추가
5. JWT 토큰 생성해서 리턴

로그인
1. 카카오 access token을 코틀린 서버에 전송
2. 카카오 access token의 유효성 검증
3. 아직 가입 안 한 회원이면 에러 리턴
4. JWT 토큰 생성해서 리턴

이에 맞게 컨트롤러와 서비스 코드를 작성한다.

카카오 access token 유효성 검증

다음은 서비스 코드다.

// 카카오 access token 유효성 검증과 동시에 id 리턴
// 주석 쓰다보니 SRP 위반했네,,?
fun getKakaoIdFromToken(kakaoAccessToken: String): Long {
        val content = getResponseFromKakao(kakaoAccessToken)
        return getIdFromKakaoResponse(content)
    }

// 카카오 url에 요청해서 응답 받아오기
    fun getResponseFromKakao(kakaoAccessToken: String): String {
        val url = URL(kakaoUrl)
        val con: HttpURLConnection = url.openConnection() as HttpURLConnection

        con.setRequestProperty("Authorization", "Bearer $kakaoAccessToken")

        val responseCode: Int = con.responseCode
        // 서비스단이라서 드디어 custom exception 던질 수 있다! 만세
        if (responseCode != HttpStatus.OK.value())
            throw BusinessException(ErrorCode.CAN_NOT_GET_KAKAO_ID_ERROR)

	// 응답 한번에 읽어서 string으로 리턴
        val br = BufferedReader(InputStreamReader(con.inputStream))
        val content = br.readText()
        br.close()

        return content
    }

// String 형의 응답 json으로 만든 뒤 파싱해서 id값 리턴
    fun getIdFromKakaoResponse(content: String): Long{
        val obj = JSONObject(content)
        return obj.optLong("id")
    }

// 카카오 access token 유효성 검증 성공 시 JWT 토큰 생성, 헤더에 담아 리턴
    fun returnWithAccessToken(response: HttpServletResponse){
        val accessToken: String = jwtProvider.createAccessToken("access token")
        response.setHeader("Authorization", accessToken)
    }

테스트 코드

이번엔 테스트 코드를 짜는데 큰 어려움을 겪었다... 카카오 access token은 유효 기간이 24시간 밖에 안되서 통합 테스트를 할 수 없다. 구글 로그인이나 페이스북 로그인은 테스트를 위해서 dummy access token을 제공해준다는데 찾아본 결과 카카오는 이런 건 없는 것 같다.
mock을 이용해서 해결하려고 했는데 service 클래스를 mock시키니까 이 안에 있는 메서드들이 모두 mock object가 되서 다른 메서드를 테스트할 수 없었다.
결국 access token이 필요 없는 기능만 테스트했다. 통합 테스트는 실제로 애플리케이션 실행 후 post man으로 요청보내는 걸로 퉁쳤다.🙁

@Test
    fun `잘못된 카카오 access token으로 회원가입 시 에러`() {
    // 코틀린은 빌더 따로 필요 없이 아래처럼 해주면 된다
        val signUpRequest = SignUpRequest(
            kakaoAccessToken = "wrong access token"
            , positionId = 1L
            , nickname = "nickname")

        val content = jacksonObjectMapper().writeValueAsString(signUpRequest)

        mockMvc
            .perform(MockMvcRequestBuilders.post("/sign-up")
                .contentType(MediaType.APPLICATION_JSON)
                .content(content))
            .andExpect(status().isInternalServerError)
            .andExpect(MockMvcResultMatchers.jsonPath("$.code")
                .value(ErrorCode.CAN_NOT_GET_KAKAO_ID_ERROR.code))
            .andExpect(MockMvcResultMatchers.jsonPath("$.message")
                .value(ErrorCode.CAN_NOT_GET_KAKAO_ID_ERROR.message))
            .andDo(print())
    }

하나의 클래스에서 어떤 오브젝트는 mock화 시키고 싶고 어떤 오브젝트는 실제로 사용하고 싶으면 stub을 사용하라고 했던 글을 봤던 기억이 있는데 이왕 이렇게 된 거 다음 공부는 stub으로..!

후기

점점 코틀린의 매력을 알 것 같다! 이러다가 다시 자바로 돌아가면 승질날 수도 있을 것 같다. 자바였다면 서드 파티를 넣어야 되거나 길게 코드를 작성해야 할 기능들이 코틀린은 그냥 된다! 빌더에도 반했고 getter, setter 따로 없는 거에도 반했다..❤️ null 없는 것도 final이 기본인 것도 참 멋진 녀석

profile
백엔드 개발자입니다.

0개의 댓글