240530 게임 뉴스피드 프로젝트 - 리팩토링하고 완성도 높이기

노재원·2024년 5월 30일
0

내일배움캠프

목록 보기
50/90

AuthService 분리하기

어제 Jwt 인증을 단순히 유저 정보가 나오니 UserService에서 진행했었는데 이걸 AuthService로 분리하기로 했다. 나중에 인증 로직은 얼마든지 커질 수도 있고 OAuth를 구현하게 되면 그것도 여기다가 집어넣어서 위임해야하지 않을까 싶어 결정했는데 패키지를 마땅히 넣을 곳을 못찾아서 그냥 security에 집어넣었다.

이번 프로젝트를 하면서 느낀건 역할 위임하게 그냥 Service 하나 새로 파서 넘기는 경우가 좀 많아진 것 같다.

Repository 리팩토링

튜터링이 벌써 가물가물해지는 시점이 왔지만 아직 중요하게 생각하고 있는건 JpaRepository를 상속받은 Repository는 아주 구체적인 저수준 모듈이라는 점이다.

따라서 Repository를 감싸겠다고 프로젝트 이틀차부터인가 계속 이슈로 잡아놨고 대부분 도메인이 끝나가는 오늘 진행했다.

일단 구조는 아주 초간단하게 JpaRepositry, Repository, RepositoryImpl로 Repository는 Pojo 인터페이스고 RepositoryImpl이 JpaRepository를 주입받아서 사용하는 구조다.

한 번 더 감싸면서 뭔가 그럴싸한 변화가 생길 줄 알았는데 사실 그렇진 않았고 엄청나게 많은 서비스 로직의 변화말고는 없었다.

Repository에서도 도메인적으로 처리할만한 뭔가가 제대로 생각나면 모르겠는데 그렇지가 않아서 그냥 JpaRepository를 직접적으로 참고하지 못하게 틀어막았을 뿐인 모양새가 됐지만 팀원분들에게 리뷰하며 이유를 설명하니 DIP가 되면서 구분이 됐다는 점을 이해해주셨다.

기왕 리팩토링 한거 내 빈약한 상상력으로 최대한 해보는 것보다 조금 더 이 저장소의 개념과 꿀팁을 확실히 조사해봤으면 좋았을텐데 하는 아쉬움이 남는다.

Swagger에 Authorization Header 추가하기

이건 사실 어제부터 고생하던 문제인데 오늘에서야 성공했다. Swagger를 버리고 Postman이 쓰고 싶어지는 순간이 꽤 많았는데 Swagger가 명세는 잘 해놓긴 했으니 최대한 써먹어보기로 하고 계속 진행했다.

우선 문제는 단순히 @RequestHeader("Authorization") 으로 생성한 Swagger의 Field는 Authorization을 제대로 넣어주지 않는다는게 문제였다. 대체 왜 그런걸까? 이건 아직도 모르겠다.

어쨌든 그렇기 때문에 Postman처럼 Header를 전역적으로 걸어놓고 계속 Token을 쓸 수 있게 하는 경우가 많아 그렇게 하려고 했는데 레퍼런스가 적거나 Swagger 버전이 구버전이라 Config이 달라져서 그냥 에러만 나는 경우가 있었다.

결과적으로 해결한건 그냥 신버전의 Config 방법이었다.

@Configuration
@OpenAPIDefinition(
    info = Info(title = "Gamenome API", description = "Gamenome API schema", version = "1.0.0"),
    security = [SecurityRequirement(name = "JWT")]
)
@SecurityScheme(
    name = "JWT",
    type = SecuritySchemeType.APIKEY,
    `in` = SecuritySchemeIn.HEADER,
    paramName = "Authorization"
)
class SwaggerConfig

그냥 Header에 이름이 Authorization인 필드를 넣고 인증하는 건데 이게 제일 간단하고 잘 처리됐다.

SecurityRequirement, SecurityScheme를 정의해서 Swagger-ui 우측 위에 Authorize 버튼이 생기고 대충 Accesstoken 넣어서 쓰면 모든 호출에 Header가 들어간다.

그런데 쓸 때는 여전히 @RequestHeader를 쓰면 쓸 데 없이 필드가 추가로 보여서 request: HttpServletRequest를 받아서 request.getHeader("Authorization")로 인증 토큰을 받아왔다.

이건 Swagger-ui때문에 바꾼 방식이지 원래는 @RequestHeader 한방이면 처리 가능하기 때문에 나중엔 바꿀 생각이다.

JWT를 통한 로그아웃 방법은?

signOut 로직을 구현하려다가 실패했다. 단순히 답이 나오는 영역이 아니었다.

내가 찾아보기로는 세 가지 방법을 봤는데

  1. 클라이언트에서 로그아웃하면 클라이언트가 그냥 Token을 소멸시킴
  2. 토큰 블랙리스트 테이블을 운영함
  3. Refresh token 발급을 중단시켜서 Access token의 말소를 기다림

그런데 지금 나는 Access token만 발급하고 토큰 블랙리스트를 운영해도 자동으로 expire 시킬 수도 없고 클라이언트는 없다.

그래서 구현 비용을 생각해서 그냥 이번에는 관두기로 했다. 생각보다 이슈가 큰 줄 몰랐다.

여담으로 2번 블랙리스트는 JWT에 관련한 레퍼런스를 볼 때 JWT는 서버의 부담을 줄이기 위해 만들어진 건데 서버에서 토큰을 즉시 만료시킨다던가 하는 로직을 추가하면 의미가 적어진다는 얘기를 본 적이 있다.

그래서 저 세가지를 보고 그냥 1, 3번을 종합해서 쓰는게 그나마 의미있을지 고민이 살짝 됐다.


코드카타 - 프로그래머스 둘만의 암호

두 문자열 sskip, 그리고 자연수 index가 주어질 때, 다음 규칙에 따라 문자열을 만들려 합니다. 암호의 규칙은 다음과 같습니다.

  • 문자열 s의 각 알파벳을 index만큼 뒤의 알파벳으로 바꿔줍니다.
  • index만큼의 뒤의 알파벳이 z를 넘어갈 경우 다시 a로 돌아갑니다.
  • skip에 있는 알파벳은 제외하고 건너뜁니다.

예를 들어 s = "aukks", skip = "wbqd", index = 5일 때, a에서 5만큼 뒤에 있는 알파벳은 f지만 [b, c, d, e, f]에서 'b'와 'd'는 skip에 포함되므로 세지 않습니다. 따라서 'b', 'd'를 제외하고 'a'에서 5만큼 뒤에 있는 알파벳은 [c, e, f, g, h] 순서에 의해 'h'가 됩니다. 나머지 "ukks" 또한 위 규칙대로 바꾸면 "appy"가 되며 결과는 "happy"가 됩니다.

두 문자열 sskip, 그리고 자연수 index가 매개변수로 주어질 때 위 규칙대로 s를 변환한 결과를 return하도록 solution 함수를 완성해주세요.

문제 링크

fun solution(s: String, skip: String, index: Int): String = ('a'..'z')
    .filterNot { skip.contains(it) }
    .let { actualAlphabetList ->
        s.map { actualAlphabetList[(actualAlphabetList.indexOf(it) + index) % actualAlphabetList.size] }
    }.joinToString("")

코드가 생각보다 짧길래 일부러 더 줄여서 써봤다. 갑자기 하려니 마음에 드는 코드는 아니긴 했다.

문제는 꽤 쉬웠고 그런데 이전에 비슷한 문제를 풀어본 것 같은데 정확히는 기억이 안나서 제출하고나서 다른 답안을 보니 대부분 엇비슷한 로직이라 크게 이슈되는 부분은 없었다.

indexOf를 반드시 써야하는가의 문제를 좀 고민했었는데 이것도 다른 대책은 찾지 못했다.

0개의 댓글