2024-07-15 - 2024-12-13
101 일.
지난 주 금요일을 마지막으로 길면 길었던 데브코스 과정을 마무리 하였습니다.
끝나고 돌아보니 만족스러웠던 부분, 아쉬웠던 부분 모두 또렷이 기억나네요.
이번 포스팅은 그 모두를 기억하기 위해 마지막으로 진행했던 프로젝트와 데브코스 전체를 돌아보는 글을 적고자 합니다.
저희 팀의 프로젝트 주제는 포트폴리오 공유 & 자기계발 구인 플랫폼
이었습니다.
사용자는 자신의 포트폴리오를 게시해 다른 사용자로부터 피드백을 받을 수 있고, 직종에 맞는 자기계발 구인 게시글을 올려 네트워킹을 도모하는 플랫폼 이었습니다.
저는 서비스에서 다음 역할을 담당해 프로젝트를 진행하였습니다.
CI
파이프라인 구축OAuth 2.0
을 이용한 회원가입 • 로그인JWT
기반 사용자 인증User
도메인 기능MDC
를 이용한 요청 도메인별 로그 분리 저장
![]() | ![]() |
---|
이 중 특히 공을 들인 부분은 OAuth 2.0 • JWT 통합
과 MDC 로그 분리
였습니다.
OAuth
를 이용한 소셜 로그인은 남들이 자주 사용하는 것만 봐왔지, 제가 직접 만들어 사용하는 것은 처음이었습니다.
그래서 OAuth
의 전반적인 이해가 필요하였고 다음 영상을 참고해 공부하였습니다.
이를 통해 소셜 로그인 자체는 성공적으로 구현하였으나, 로그인 후 자체 JWT
를 발급하는 부분이 문제되었습니다. OAuth
의 경우 프론트에서 href
로 인증을 진행하고 성공시 특정 url
로 redirect
되기 때문입니다.
이를 해결하기 위해 OAuth 로그인 성공 시
자체 임시 토큰을 url
에 넣어 토큰 발급 Endpoint
에 redirect
되는 방안을 고안했습니다.
@Slf4j
@Component
public class OAuth2LoginSuccessHandler
extends SimpleUrlAuthenticationSuccessHandler {
private final JwtUtils jwtUtils;
private final String successRedirectUri;
/**
* 로그인 성공해서 임시 토큰으로 진짜 토큰들 발급하는 {@code /token/issue?token=} API 로 redirect
*/
@Override
public void onAuthenticationSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication
) throws IOException, ServletException {
CustomOAuth2User customUserDetail
= (CustomOAuth2User) authentication.getPrincipal();
String temporaryToken
= jwtUtils.createTemporaryToken(customUserDetail.getUser());
log.info("Temporary token issued in CustomLoginSuccessHandler - token: {}", temporaryToken);
// 임시 토큰으로 access, refresh 토큰 발급하는 endpoint 로 redirect
// local profile 은 back 으로, deploy 는 프론트 주소로
response.sendRedirect(successRedirectUri + "?token=" + temporaryToken);
}
}
이를 통해 OAuth
인증의 강점은 살리면서 JWT
통합을 성공적으로 완료할 수 있었습니다.
저희 팀은 Github Action
과 Docker
를 이용한 CD
파이프라인을 구추하였습니다.
그런데 실제 배포해 프론트와 연결하다 보니 다양한 에러가 발생하였고, 그 에러를 추적하는데 어려움을 겪었습니다.
Docker
로 서버를 올렸기 때문에 docker logs
명령어로 로그를 직접 볼 수 밖에 없기 때문이었습니다.
그래서 이를 개선하고자 Mapped Diagnostic Context
를 이용한 요청 도메인별 로그 분리
를 진행하였습니다.
배포 서버에 도메인별 로그가 저장된 모습
/**
* {@code Mapped Diagnostic Context} 이용한 도메인별 로그 저장(은 아니긴 한데 비슷한) {@code filter}
*/
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 이러면 filter 중에서도 가장 빠른? 필터로 되는듯. 신기하네
public class MDCLoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
// 요청별 랜덤 uuid 생성 & 저장
String requestUUID = UUID.randomUUID().toString();
request.setAttribute("custom-request-uuid", requestUUID);
log.info("REQUEST {} \"{}\" earned custom UUID : {}",
request.getMethod(), request.getRequestURI(), requestUUID);
try {
this.configureLogDirViaUri(request);
this.logNewLines();
log.info("============== REQUEST [{}] START ==============", requestUUID);
filterChain.doFilter(request, response);
} finally {
log.info("============== REQUEST [{}] END ==============", requestUUID);
this.logNewLines();
MDC.clear();
}
}
// uri 별 도메인 파악해서 MDC key 넣어주기
private void configureLogDirViaUri(HttpServletRequest request) {
String uri = request.getRequestURI();
DomainType domainType = DomainType.of(uri);
MDC.put("DOMAIN_LOG_DIR", domainType.getDomainLogDir());
log.info("Domain logging directory has been set to : [{}]", domainType.getDomainLogDir());
}
private void logNewLines() {
log.info("");
log.info("");
}
}
백엔드 서버로 요청이 들어올 경우 요청별 고유한 UUID
를 생성 • 저장해 요청의 시작과 끝을 확실히 파악할 수 있도록 구성하였습니다.
또한 요청 처리 중 에러가 발생하면 따로 exception
폴더에 집계하도록 하여 에러 추적에 용이하도록 Logback
을 구성하였습니다.
배포 로그에서 요청 UUID 를 통해 에러를 추적하는 모습
이를 통해 원활한 에러 추적이 가능하였고 프론트와의 연결을 마무리할 수 있었습니다.
저는 스스로 최종 프로젝트를 통해 배운 점이 정말 많다고 생각합니다.
OAuth 2.0
, Logback
등 들어보기만 하던 내용들을 직접 구현하였으며, 앞서 언급하진 않았지만 QueryDSL 을 이용한 NoOffset 조회
, Spring Security 구성
등을 진행하였기 때문입니다.
비록 최종 프로젝트에서 획기적이고 독특한 기능을 담당한 것은 아니지만, 스스로 성장하고 있음을 확신하는 경험이었습니다.
돌이켜 보면 6 개월 전 자신이 얼마나 무모했는지 알 수 있었습니다.
백엔드의 ㅂ
도 모르던 초심자 주제에. 혼자서 이 모든 것을 독학하려 했다니. 정말 말도 안되는 하룻강아지의 객기였다고 생각합니다. 만약 데브코스에 참여하지 않았다면 절대로 지금의 자신
이 되지 않았으리라 확신합니다.
하지만 그렇다고 "데브코스"
그 자체를 찬양할 생각은 없습니다.
수강하며 불만족스러운 부분이 명확하게 존재했었고, 무엇보다 학습
의 본질은 자기 자신에게서 찾아야 한다 생각하기 때문입니다.
분명히 데브코스를 수강하며
성장한 것은 맞지만, 데브코스 만으로
성장한 것은 아니라 생각합니다.
데브코스가 학습
에 도움을 준 것은 맞지만, 같이 성장하는 동료
, 강사님의 피드백
, 그리고 스스로 학습하고자 하는 의지
가 없었다면, 절대로 이만큼 성장할 수 없었다 단언할 수 있습니다.
그래서 저는 데브코스
를 좋은 부트캠프
라 말하고 싶지 않고, 백엔드를 향한 좋은 첫걸음
이라 말하고 싶습니다.
데브코스를 통해 스스로 부족한 부분이 정말 많다고 느꼈습니다.
확실히 비전공자와 전공자의 4 년 차이는 무시할 수 없음을 느꼈고, 백엔드 이론과 기술, 그 모든 부분에서 뒤쳐져 있음을 체감하였습니다.
하지만 이럴 때 일수록 다시 기본으로 돌아가야 된다고 생각합니다.
Kafka
, K8s
등 취업에 매력적인 기술들 이지만 이를 자기것으로 만들기 위해선 튼튼한 기초가 필요하다 생각합니다.
그래서 이제는 온전히 독학하는 시간을 갖고자 합니다. Design Pattern
부터 시작해 Spring Boot, Security
, RDBMS
까지 기초적이지만 핵심적인 내용을 공부하고자 합니다.
물론 장담할 수 없을 정도로 오랜 시간이 걸리겠지만 그래야 속이 편한걸 어쩌겠습니까.
하여간 이 물리학 성격은 죽지를 않네요.
그럼 언젠가 더 성장한 자신을 기원하며 글을 마치도록 하겠습니다.