*이 글은 7월 한 달간 진행한 '이음새 프로젝트'의 트러블 슈팅을 담고 있습니다.
그 당시 노션에 기록했던 내용을 블로그로 옮기는 과정에서 다듬고 정리한 결과물입니다.
트러블 슈팅을 해보자!
첫 프로젝트 진행 중 당연히 막히는 부분이 너무나도 무궁무진했다. 그럴 때마다 개발을 먼저 시작한 친구인 준섭이한테 물어보았다.
근데 질문을 하면서도, 내가 막히는 부분이 뭔지,정확히 뭐가 안되는지, 뭘 해봤는지 에 대해 생각 조차 안하고 막연하게 질문을 하니 대답해주는 친구도 잘 몰랐고 나 또한 내가 뭘 하고 있는 건지 한 마디로 이리저리 프로젝트에 끌려다니고 있었다.
준섭이(잘생기고, 멋있고, 성격좋고 ,젠틀하고, 랩도 잘하고 )의 조언으로 트러블 슈팅을 하면서 기록해보라 하였다.
우선 그 전에, 트러블 슈팅이 뭔지 알아보자!!
-트러블슈팅 : 쉽게 말해 문제 해결 과정을 의미
- 오류 발견: 코드에서 버그나 에러가 발생했을 때
- 원인 파악: 그 문제가 왜 일어났는지 이유를 찾는 과정
- 해결책 모색: 문제를 해결할 수 있는 방법을 찾고 적용하는 과정
- 테스트와 확인: 문제가 실제로 해결되었는지 확인하는 단계
* 오류(근데 이제 화남을 곁들인)로 인한 날 것의 내용이 있을 수 있습니다.. 참고 바람!
(7월 13일)
🤦 회원가입 시 닉네임 설정 칸에서 회원가입이 안됨 → json 반환이 안되는 거 같다.
-“SyntaxError: Unexpected token '<', "<! DOCTYPE "... is not valid JSON “
내가 자주 보는 이 오류의 본질부터 좀 알아보자.
- 클라이언트(브라우저)는 서버에게 특정 형식의 데이터(JSON)를 요청 이는 마치 편지를 기대하는 것.
- 하지만 서버가 전혀 다른 형식의 데이터(HTML)를 보냄. 이는 편지 대신 택배 상자를 받은 것과 같다.
- 브라우저는 이 데이터를 JSON으로 해석하려고 시도한다.(JSON.parse 함수 사용). 이는 편지를 읽으려는 방식으로 택배 상자를 열려고 하는 것과 같다.
- 당연히 이 시도는 실패합니다. HTML은 JSON이 아니기 때문. 이는 택배 상자를 편지처럼 읽을 수 없는 것과 마찬가지
결과적으로, 브라우저는 "이건 내가 기대한 형식이 아니야!"라고 말하면서 오류를 발생시킨다. 이것이 바로 우리가 보고 있는 "Unexpected token '<'" 오류의 본질!!
우선 API를 호출 할 때 제대로 하는지부터 체크하자 API 체크된다 확인
fetch('/api/users', {
method: 'POST', // HTTP 메서드를 POST로 설정
headers: {
'Content-Type': 'application/json', // 요청 본문이 JSON 형식임을 서버에 알림
'X-CSRF-TOKEN': getCsrfToken(), // CSRF 토큰 포함 (보안을 위해)
},
body: JSON.stringify(completeData) // JavaScript 객체를 JSON 문자열로 변환
})
users로 포스트 요청으로 제이슨 보냄,
.then(response => {
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("application/json")) {
console.log('Received JSON response');
return response.json();
}
// ...
})
-Json이란? 다시 정리해보자.
- 클라이언트 -> 서버 (사용자 정보 전송)
- 서버 처리 (정보 검증 및 저장)
- 서버 -> 클라이언트 (처리 결과 응답)
1번
클라이언트 -> 서버:
- 사용자가 회원가입 폼에 정보를 입력합니다 (이름, 이메일, 비번, 닉네임)
- '가입하기' 버튼을 클릭하면, JavaScript가 이 정보를 JSON 형태로 변환
- 이 JSON 데이터가 서버로 전송
2번
서버 처리:
- 서버가 JSON 데이터를 받아 처리
- 데이터 유효성을 검사하고, 데이터베이스에 저장
- 처리 결과에 따라 응답을 준비.
3번
서버 -> 클라이언트:
- 서버가 처리 결과를 JSON 형태로 클라이언트에게 전송
- 클라이언트의 JavaScript가 이 JSON 응답을 받아 파싱
- 파싱 된 데이터를 바탕으로 사용자에게 결과를 표시
우선 이건대 CSRF 비활성화하면 회원가입이 되고 로그인이 리다이렉트 무한루프를 겪는다.
근데 또 CSRF를 활성화하면 로그인은 되는데 회원가입 때 SyntaxError: Unexpected token '<', "<! DOCTYPE "... is not valid JSON 이 오류가 생겨 CSRF활성화 이후 토큰 값을 헤더에 기재해서 넣어도 똑같음. 그럼 CSRF 비활성화를 때리고 로그인 로직을 수정해 보는 방법으로 하는 건 어떨까?
🔑문제해결
ok csfr 토큰을 우선 그냥 지우니까 로그인도 됨
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
CSRF 중요하다는데 지금은 구현이 먼저임 나중에 공부하자
토큰 문제는 일단 뒤로 젖혀두자. 이게 맞나? ㄱㅊ을듯 왜냐면 인증/인가 문제부터 해결하는 게 낫잖아
왜냐면 토큰은 인증 /인가 이후에 발급받는 거잖아
🤦 소셜로그인 이후에 닉네임(/signupNickname)으로 넘어가게끔 설정은 해놨는데 여기서 닉네임을 치면 또 오류가 발생한다.



똑같이 /siginupNickname으로 왔는데 안된다? 이러면 여기로 리다이렉트 될 때 문제 아닐까? 왜냐면
자체 회원가입과의 차이는 소셜에서 넘어온 거니까
(아니 근데 소셜로 하니까 또 JWT토큰 생성 되네 뭐야 ;; 우선 뒤로 생각하고)
그럼 데이터가 제대로 안 박혔나? 토큰 전송이 안 됐나? 로그 보니까 리다이렉트 시작하고 그때부터 또 토큰을 못 찾네
한 번 이거를 고쳐보자 이 백엔드 로직을 어떻게 고쳐야 될지를 모르겠어요
우선 지금 토큰과 데이터를 /signupNickname에 전달 즉 지금 내가 해야 될 핵심은 "일시적인 상태 저장과 안전한 전달”을 해야 되잖아
안전한은 솔직히 지금으로선 무리다.
세션으로 임시적인 저장 → 소셜로그인 여부 판단 → true 반환 →
왜냐면 사실 소셜로그인 이후 홈화면 리다이렉트 했으면 그냥 로그인인데 나는 지금 소셜로그인(사실 로그인 상태가 아닌 거야, 회원가입을 또 2차 진행해야 함) 소셜로그인 → 닉네임 설정 ->회원가입 →로그인인 거잖아 그럼 여긴 홈화면으로 바로 가야 되고
자체회원가입 폼 →닉네임 설정 →회원가입 →로그인창 가서 다시 로그인하기 →홈화면 이거잖아 여기서 닉네임 설정 칸을 같이 공유해도 되는 건가?.. 그럼 여기서 닉네임 설정칸의 로직을 소셜로그인 시 그다음은 홈으로 자체회원가입이면 그 다음은 로그인으로 이런 로직을 따로 구현해야 돼? 흠..
그럼 컨트롤러에서 대충… 이러면 되나? 흐음
@PostMapping("/set-nickname")
public String setNickname
(@RequestParam boolean isSocialLogin) {
if (isSocialLogin) {
return "redirect:/home";
} else {
return "redirect:/login";
}
지피티 도움 받을까 시발 어쩌지.. 우선 오늘 잘래….. 쏘 피곤
7월 14일
🤦 네이버로그인은 안됨. 구글은 되는데 무슨 차이로 인하여 안될까?
-닉네임 메서드 칸에 오류가 있다고 뜬다
public boolean hasNickname(String userNickname) {
User user = userRepository.findByUserNickName(userNickname)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return user.getUserNickName() != null && !user.getUserNickName().isEmpty();
}
이 메서드에 오류가 있다.
내가 만든 이 메서드는 저장소에서 닉네임을 조회한 이후에 검색된 사용자가 없는 예외를 던진다 “유저가 없어요~” 그 뒤에 만약 닉네임 값이 null값도 아니고 빈 문자열도 아니면 true를 반환시킴
- 메서드의 예상 동작:
이렇게로만 수정해서 닉네임 존재여부만 확인하자
근데 그럼 왜 구글은 이 메서드 수정 없이 됐지만 네이버소셜로그인은 이 메서드가 문제였을까?
근데 이 메서드 사실 필요 없는 거 같다 왜냐면 나는
private void validateDuplicateUser(User user) {
//중복확인 사용자를 검증하는 메서드
if (checkDuplicate("userId", user.getUserId())) {
throw new IllegalStateException("이미 존재하는 아이디입니다."); }
//아이디 중복확인 검사 if (checkDuplicate("userNickName", user.getUserNickName())) {
throw new IllegalStateException("이미 존재하는 닉네임입니다."); }
//닉네임 중복확인 검사 if (checkDuplicate("userEmail", user.getUserEmail())) {
throw new IllegalStateException("이미 등록된 이메일입니다."); }
//이메일 중복확인 검사
이렇게 중복확인 로직은 이미 뚫어놨었기 때문이다 즉 삭제하고
String userNickname = customUserDetails.getUserNickName();
boolean hasNickname = userNickname != null && !userNickname.trim().isEmpty();
log.info("사용자 닉네임: {}, 닉네임 존재 여부: {}", userNickname, hasNickname);
// 리다이렉트 URL 설정if (hasNickname) { redirectUrl = "/";
log.info("사용자가 닉네임을 가지고 있습니다. 메인 페이지로 리다이렉트합니다.");
} else {
redirectUrl = "/signupNickname";
log.info("사용자가 닉네임을 가지고 있지 않습니다. 닉네임 설정 페이지로 리다이렉트합니다.");}
이렇게 CustomSuccessHandler에서 직접 문자열로 체크하는 방식으로
소셜로그인 시 바로 문자열로 체크해서 닉네임이 있다면 홈으로, 없다면(이건 신규겠지) 닉네임 설정 페이지로 넘기는 방식으로 하자
🤦 소셜로그인으로 들어올 때 닉네임 설정칸으로 넘어온 이후 회원가입이 안됨
1-1이 회원가입 폼이고 1-2에 따로 닉네임 설정칸을 뚫어서 소셜로그인 시는 이메일과 이름을 가지고 오니까
1-2로 바로 이동해서 닉네임만 설정해서 가입시키는 절차를 진행 중.
기존 회원가입은 잘 되는데 여기서 안 되는 이유는 무엇일까?
닉네임 설정페이지로 소셜로그인 시에 가져온 토큰이나 데이터를 못 가져왔나? 콘솔 보면 여기가 오류 난다고 함! 이 줄은 filterChain.doFilter(request, response);

우선 소셜로그인 시 비밀번호가 NUll값으로 넘어가는데 회원가입은 password를 가져가야 되는 이슈가 발생함. 그럼 password null값을 허용하거나 PW인증을 피하는 로직을 구현해야 될까?
****그냥 가상의 비밀번호를 설정하는 로직을 설정해 볼까?~ 이러면 null값을 그냥 메꿀 수 있으니까 Dummy password로 설정해 보자 우선 userform의 boolean 타입으로 socialLogin 여부를 세팅
if (form.isSocialLogin()) {
// 소셜 로그인의 경우 임의의 비밀번호 생성
String dummyPassword = "SOCIAL_" + form.getUserId() + "_" + System.currentTimeMillis();
user.setUserPw(bCryptPasswordEncoder.encode(dummyPassword));
} else {
// 일반 로그인의 경우
if (form.getUserPw() == null || form.getUserPw().isEmpty()) {
throw new IllegalArgumentException("비밀번호는 필수 입력 항목입니다.");
}
user.setUserPw(bCryptPasswordEncoder.encode(form.getUserPw()));
}
이 조건문을 설정했다. 근데 여기서 의문이 소셜로그인인 지 아닌지는 어떻게 확인시켜줄 건데 그전에?

역시나 일반로그인으로 간주하고 예외를 띄운다. 소셜로그인을 진행할 때
여기서 소셜로그인이야라고 넘겨주는 로직을 구현해야겠음.
우선 지금 토큰과 데이터를 /signupNickname에 전달 즉 지금 내가 해야 될 핵심은 "일시적인 상태 저장과 안전한 전달”을 해야 되잖아 안전한은 솔직히 오버임 모름 결국 이 문제이다 일시적인 상태 저장과 전달의 방법은 무엇이 있을까?
-멘토님의 조언 - 스프링에서 일시적으로 데이터를 세션에 저장시키는 것이 있다 함 ***
1.HttpSession 사용: 스프링의 HttpSession을 사용하여 임시 데이터를 저장 구글링한 결과 이 방법.
2.Spring Security의 SecurityContextHolder 사용: 인증 정보를 임시로 저장할 때 유용
3.Redis를 이용한 분산 세션 저장소: 더 확장성 있는 방법으로, Redis를 세션 저장소로 사용할 수 있습니다.
4.JWT 토큰에 임시 데이터 포함: JWT 토큰에 필요한 임시 데이터를 포함시키고, 클라이언트에서 이를 다시 서버로 전송하게 할 수 있다.
우선 3번의 방식에 Redis라는 워딩조차 모르니 스킵하고
멘토님이 추천해 주신 1번의 방법으로 진행해 보자
근데 잠깐만 로그인 로직에 쓰였던 JWT vs Session 공부했던 그 세션과는 다른 개념일까? 같은 개념의 session이라면 같이 운용해도 되는 걸까? 알아봐
JWT와 HttpSession을 함께 사용하는 방식:
- JWT 사용:
- HttpSession 사용:
예상 플로우 -
- 소셜 로그인 시작 → OAuth2 인증
- 서버에서 사용자 정보 받고
- HttpSession에 사용자 정보 임시 저장 (이메일, 이름 데이터)
- 닉네임 설정 페이지로 리다이렉트
- 닉네임 입력 페이지 로드 시, 세션에서 임시 저장된 정보 확인
- 닉네임 입력 및 제출
- 서버에서 세션의 정보와 입력받은 닉네임을 합쳐 회원가입 완료.
- 완성된 사용자 정보로 JWT 생성
- JWT를 클라이언트에 전송 (쿠키로)
- 세션에서 임시 저장된 사용자 정보 삭제
- JWT를 사용하여 인증 **근데 세션이랑 JWT 같이 운용해도 되나 의문
🤦 JWT 생성 이후, 토큰을 못 찾아옴

// 쿠키에서 토큰 찾기 추가
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("Authorization".equals(cookie.getName())) {
token = cookie.getValue();
log.info("Authorization 쿠키에서 토큰 추출: {}", token);
break;
}
}
}
쿠키에서도 토큰을 추출하는 걸로 수정해 봄.

토큰 추출은 됐다만 토큰이 만료 됐다고 뜬다 ( 근데 /login)으로 갔을 때부터 토큰이 추출이 되나;…

-/login으로 매핑되자마자 토큰이 추출돼요
문제가 너무 많아요 ㅠㅠ
String requestUri = request.getRequestURI();
if (requestUri.matches("^\\/login(?:\\/.*)?$")) {
filterChain.doFilter(request, response);
return;
}
if (requestUri.matches("^\\/oauth2(?:\\/.*)?$")) {
filterChain.doFilter(request, response);
return;
}
🔑문제 해결
:필터 추출 되기 앞에 /login과 oauth2 경로로 오는 것은 필터를 거치치 않게끔 설정.
우선순위 또 벗어나려 했다. 인증 인가부터..
(7월 15일)
🤦 소셜로그인 → /signupNickname으로 못 가는 오류
지금 1-1이 회원가입 페이지(이름 이메일, 비밀번호 입력)이고 1-2이 닉네임 설정 페이지(닉네임 따로 설정 )입니다! 소셜로그인을 한 사람들은 1-2로 넘어가게끔 하고 싶은데 소셜로그인 정보를 못 받아오는 게 문제입니다 자체 회원가입 한 사람은
document.getElementById('signupFormStep1').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const userData = Object.fromEntries(formData.entries());
console.log(userData);
debugger;
localStorage.setItem('userData', JSON.stringify(userData));
window.location.href = '/signupNickname';
/////////////////////////////////////////
document.geElementById('signupFormStep2').addEventListener('submit', function(e) {
e.preventDefault();
const nickname = document.getElementById('userNickName').value;
const userData = JSON.parse(localStorage.getItem('userData') || '{}');
const completeData = { ...userData, userNickName: nickname };
소셜로그인도 이렇게 넘어가게끔, 똑같이 localStorage에 담아 오는 방법으로 진행해도 될까요? 1-2(닉네임 페이지에서) 회원가입 → api/users 호출해서 한 번에 처리합니다 이거를 닉네임 페이지에 api 엔드포인트를 따로 설정해서 진행하는 게 훨씬 깔끔할까요?
(7월 17일)
🔑문제 해결
임시로 데이터를 저장 + 전달에 엄청난 어려움을 겪었는데 방법이 있었다. 그냥 칼럼을 하나 파서 “회원가입 완료여부” (타입은 boolean)으로 두고
회원가입 완료되지 않는 사람은 즉, 1단계(이름 이메일 비밀번호 입력 )만 처리한 사람은 false를 반환해서 2단계(닉네임 설정) 페이지로 넘기고
소셜로그인 또한 마찬가지로 1단계로 여기고 2단계로 넘기면 됐었다
그럼 자동으로 JPA 업데이트를 통해 칼럼에 임시로 1단계만 처리한 데이터를 2단계인 닉네임까지 추가해서 회원가입 완료로 하고 최종 회원가입 완료!
간단하게 정리하면:
- "회원가입 완료여부" 컬럼 추가 (boolean 타입)
- 1단계만 완료한 사용자는 false 반환
- false인 경우 2단계(닉네임 설정) 페이지로 이동
- 2단계 완료 시 JPA로 자동 업데이트
* 회원가입 완료!!!!! DB에도 잘 들어간다!!!!!!!!******

내가 하고 싶은 기능의 순서도
- 사용자 정보 입력 ( 이름, 이메일, 비밀번호) - 중복확인 체크
- 비밀번호 암호화
- 소셜로그인 ( 사실상 회원가입 1단계)
- 선택한 소셜 플랫폼(예: Google, Facebook 등)으로 리다이렉트
- 소셜 플랫폼에서 인증 후 액세스 토큰 받기
- 받은 토큰으로 사용자 정보 요청
- 해당 정보로 자체 데이터베이스에 사용자 생성 또는 기존 계정과 연동
- 닉네임 설정 (회원가입 2단계)
- 닉네임 중복 확인
- 자체 회원가입에서 앞서 가져온 데이터(이름, 이메일, 비밀번호)와 취합해서 회원가입
- 소셜 로그인에서 앞서 가져온 (이름 이메일)와 취합해서 회원가입 (오류) // →(완료) **임시데이터를 저장하는 칼럼을 설정하여 임시데이터를 저장시킨 후 idx와 함께 닉네임을 반환하여 넘기자. (ing) / 완료
소셜로그인은 닉네임 설정 완료 이후 (닉네임 여부확인) 후 홈으로 로그인 자체회원가입은 회원가입하고 자체 폼로그인
- Login 필터 통한 인증 및 JWT 토큰 생성(오류) → 세션으로 돌리자..
- 사용자 인증 확인 (비밀번호 확인 또는 소셜 인증)
- 인증 성공 시 JWT 토큰 생성 →(일반 로그인 시 오류)
- 토큰에 사용자 식별 정보 및 권한 포함
- JWT 필터를 통한 로그인 상태 유지(오류) login 매핑부터 jwtFilter 시작됨
- 클라이언트에서 요청 시 JWT 토큰을 헤더에 포함 (쿠키)
- 서버에서 JWT 필터를 통해 토큰 유효성 검사
- 유효한 토큰일 경우 요청 처리, 그렇지 않으면 인증 오류 반환
- 토큰 만료 시 갱신 로직 구현 (선택사항)

/login 매핑 시부터 바로 3번 시작이 된다 왜 그럴까?
- 문제의 원인:
- 해결 방안: a. JWT 필터 적용 범위 제한: b. 공개 URL 설정: c. 토큰 존재 여부 확인:
소셜로그인, 일반로그인 순서부터 다시 짚어보자
CustomOAuth2 UserService - >소셜 로그인을 위한 서비스 로직.
- OAuth2 인증 후 소셜 서비스(Google, Naver 등)에서 제공하는 사용자 정보를 받아온다.
- 받아온 정보를 바탕으로 애플리케이션에서 사용할 UserForm객체를 생성합니다.
- userService.socialSignup메서드를 호출하여 소셜 로그인 사용자를 데이터베이스에 저장하거나 업데이트합니다.
- 최종적으로 CustomOAuth2User 객체를 생성하여 반환합니다. 이 객체는 Spring Security에서 인증된 사용자 정보로 사용
String 타입 principal 처리를 추가한 이유를 상세히 설명:(GPT)
- 문제의 원인: 처음에 보내주신 로그에서 "알 수 없는 사용자 타입: java.lang.String"이라는 경고가 발생했습니다. 이는 시스템이 예상하지 못한 String 타입의 principal을 받았다는 의미입니다.
- 일반적인 상황: 보통 Spring Security에서는 principal이 UserDetails나 OAuth2User 인터페이스를 구현한 객체입니다. 그러나 때때로 다른 타입의 principal이 사용될 수 있습니다.
- String 타입 principal의 발생 가능성:
- 안전성 확보: String 타입 처리를 추가함으로써, 예상치 못한 상황에서도 시스템이 중단되지 않고 작동할 수 있게 됩니다.
- 디버깅 용이성: 이러한 처리를 추가하면 String 타입의 principal이 실제로 언제, 어떤 상황에서 발생하는지 파악하기 쉬워집니다.
- 유연성 증가: 다양한 인증 방식을 지원할 수 있게 되어 시스템의 유연성이 증가합니다.
하지만 이는 임시적인 해결책입니다. 장기적으로는 다음 단계를 수행해야 합니다.
- String 타입 principal이 어디서 발생하는지 정확히 파악합니다.
- 가능하다면 해당 부분을 수정하여 표준 UserDetails나 OAuth2User 객체를 사용하도록 변경합니다.
- 만약 String 타입 principal 사용이 불가피하다면, 이를 처리하는 별도의 인증 제공자나 필터를 구현하여 보다 체계적으로 관리합니다.
이렇게 함으로써 예상치 못한 상황에 대비하면서도, 근본적인 원인을 파악하고 해결할 수 있는 기반을 마련할 수 있다.
(7월 18일~7월 20일)
🙆♂️ JWT를 활용하는 API의 비즈니스 로직 다시 생각해보기.
토큰을 발급하여 활용하는 가장 대표적인 경우는 로그인과 같은 인증/인가 API다.
로그인은 일반 로그인과 OAuth를 활용한 소셜 로그인으로 나눌 수 있다.
각 방식별 비즈니스 로직은 아래와 같다.
(서비스 특성에 따라 로직은 달라질 수 있으며, Refresh Token을 활용한 방식은 포함하지 않았다.)
일반 회원가입/로그인
- 사용자의 회원가입 요청
- 요청 정보 확인하여, 기 가입 여부 확인 및 회원 정보 등록 및 성공 응답 반환
- 사용자의 로그인 요청
- 요청 정보 확인하여, 기 가입 여부 확인 및 해당 회원 정보 기반으로 Access Token 생성
OAuth 로그인
- 사용자의 회원가입/로그인 요청
- 요청 정보 확인하여, 기 회원가입 유저일 경우 로그인으로 아닐 경우 회원가입으로 처리
- 해당 사용자 데이터 기반으로 Access Token 발급
내가 하고 싶은 건 이건데
JWT를 활용한 API 방식이기에 httpBasic과 formlogin 비활성화를 안 했었어
왜냐면! 나는 formlogin을 즉 일반 로그인 (자체로그인)으로 생각하고 구현해 버렸음.
근데 이걸 하는 순간 세션로그인이 진행되는 거임! 다시 진행해 보자 일반로그인에 대한 토큰생성이 안되는데 그걸 해야 되는 듯!
- JWT 기반 로그인 (/login)
- 사용자 정보 조회 (/api/user-info - GET)
- 사용자 정보 업데이트 (/api/user-info - POST)
- 닉네임 중복 확인 (/check/userNickName/{nickname})
총 이렇게 4개의 API를 만들어야 돼 그럼 즉 /login API에 토큰 기반 인증 로그인을 설정해야 돼
이건 즉 컨트롤러에서 처리해야겠지?
❓질문 정리
-세션 → JWT 고도화 과정 진행 중 구현 실패 시 , 어떤 전략을 세워야 될지? -확장성을 고려한 ‘껍데기’ 구조란 구체적으로 어떤 요소들을 포함해야 될지?
-어떤 기준(시간적, 기술적)으로 ‘실패’ 여부를 판단해야 될지?
세션과 JWT 중 어떤 방식이 프로젝트의 장기적인 목표에 더 부합할지?
-JWT는 요즘 기본적인 로그인 요소일지 or 프로젝트마다 적합한 기술을 판단해야 될지?
즉 , 세션 vs JWT를 공부해 봤을 때 이런 소규모프로젝트엔 필요 없다 느꼈다. 도전해 보는 게 좋을지?
* 공부하는 관점에선 무조건 맞는 거 같다.
-구현만 한 오버스펙이 오히려 단점이 될지(ex. 보안문제 처리 x, 토큰 문제 처리 x JWT)
-프런트/백 구분이 없는 상태에서 첫 프로젝트를 진행ㅎ 앞으로 나아가야 될 방향은 무엇일지?
* 각자의 기능을 맡고 클라이언트 측 , 서버 로직 한 명이 처리 중 API 응답 요청까지 진행
(말이 안 되는 거 같음)ㅠㅠ
(7월 21일)
🙆♂️ 로그인 흐름 다시 생각해보기
1. 사용자 요청
사용자가 회원가입, 로그인 또는 정보를 조회/수정하는 요청을 보냄.
2. 회원가입 (일반 회원가입)
- SignController: 사용자의 회원가입 요청을 처리함.
- UserService: 요청 정보를 확인하고, 중복 검증 후 회원 정보를 등록.
- 응답으로 회원가입 성공 메시지 반환.
3. 로그인 (일반 로그인)
- LoginController: 사용자의 로그인 요청을 처리함.
- LoginFilter: UsernamePasswordAuthenticationFilter를 확장하여 사용자의 로그인 요청을 가로채고, 인증 시도.
- CustomUserDetailsService: 사용자의 인증 정보를 UserDetails로 반환.
- 인증 성공 시, LoginFilter가 JWT 토큰을 생성하고 응답 헤더에 추가.
- 응답으로 JWT 토큰 반환.
4. OAuth 로그인
- OAuth2 Controller: 사용자의 OAuth 로그인 요청을 처리함.
- OAuth2 Service: OAuth 제공자로부터 사용자 정보를 받아와서 처리.
- JWT 토큰을 생성하고 응답 헤더에 추가.
- 응답으로 JWT 토큰 반환.
5. JWT 검증
- 사용자가 로그인 후 다른 API 요청 시, JWT 토큰을 요청에 포함시켜 보냄.
- JwtFilter: OncePerRequestFilter를 확장하여 요청을 가로채고 JWT 토큰을 검증.
- 요청 처리 후 응답 반환.
6. 사용자 정보 조회 및 수정
- MainController: 사용자의 정보 조회/수정 요청을 처리함.
- UserService: 사용자 정보 조회/수정을 처리.
- 응답으로 사용자 정보 반환.
클래스별 역할 정리
- CustomOAuth2 User: OAuth2 사용자 정보를 처리하는 클래스.
- CustomUserDetails: 일반 사용자 정보를 처리하는 클래스.
- JwtUtil: JWT 토큰 생성, 검증, 추출을 처리하는 유틸리티 클래스.
- JwtFilter: JWT 토큰을 검증하고 인증 객체를 설정하는 필터.
- LoginFilter: 로그인 요청을 처리하고 JWT 토큰을 생성하는 필터.
- UserService: 사용자 회원가입, 중복 검증, 정보 조회/수정을 처리하는 서비스.

내가 하고 싶은 건 크게는 이거야
근데 나는 우선 자체회원가입폼과 소셜로그인이 있고 두 가지 경로에서 오는 닉네임설정칸(최종 엔드포인트)이 있어.
그래서 자체 회원가입, 소셜로그인을 임시 칼럼에 저장해서(회원가입 완료여부 타입으로) 설정해서 소셜로그인(이름, 이메일 가져옴) +자체회원가입(이름, 이메일, 비밀번호)이 signup1 닉네임 설정이 sinup2 이렇게 진행 중이야.
여기서 세션과정에선 잘 해결을 했는데 JWT로 고도화 중 여러 문제점에 봉착했어
근데 지금 나의 문제점은 우선
- 어떤 매핑으로 가든 토큰을 추출하려 함 + JWT필터가 시작됨 -토큰 추출을 로그인 이후만 실행되어야 될 거 같은데 말이 안 됨
- 토큰에서 추출할 때 userID, user role 이런 것들이 null값이 뜸 -애초에 폼 로그인은 또 토큰 생성조차 안됨
- 세션으로 처리할 땐 메인컨트롤러-회원 정보를 불러와서 ex) (닉네임)님! 환영합니다! -이렇게 잘 불러왔어 OAUTH2 유저는 오스 유저로 처리, 일반 사용자는 또 따로 처리 됐는데 세션 방식을 끄고 구현 중에는 일반 사용자로 치부돼버림
🙇♂️ 결론
결국 애를 먹었던 JWT를 잠깐 제쳐두고 시간상 session 방식의 로그인으로 진행하였다. 이후 리캡 과정에서 다시 JWT로 구현 시도를 해봐야겠다. 처음으로 기록한 트러블 슈팅이라 너무 러프하게 적은 경향이 있는 거 같다. 물론 누구를 보여주기 위한 것이 아닌 정말 나의 오류 해결을 위한 글이지만, 조금 더 오류에 대해 고찰을 하기 위해서라도,나중에 내가 볼 때를 위해서라도, 조금 더 깔끔히 정리하는 것이 나아보인다.
너무 재밌었다. 다음 프로젝트를 할 땐 내가 느낀 바를 적용해서, 보다 더 오류에 직면할 때 현명하게 대처할 수 있는 개발자가 되도록 노력해야겠다!!

'Project > 이음새' 카테고리의 다른 글
| 이음새 트러블 슈팅 정리(공통 닉네임 등록 페이지 이동 중 오류 발생) (0) | 2024.08.30 |
|---|---|
| [Project] 이음새 - 개선 사항 1차 (0) | 2024.08.26 |
| [Project] 이음새 프로젝트 관련 글 정리 (0) | 2024.08.07 |
| 이음새 - 프로젝트 (첫 팀프로젝트!) (0) | 2024.07.01 |