...는 과제할 시간이 부족해서 Skip하도록 하겠다.
맞든 틀렸든 일단 연관관계를 아래와 같이 설정해봤다.
[해당 이미지는 IntelliJ에서 내가 쓴 객체의 연관관계를 알아서 읽어서 만들어준 다이어그램이다.]
왼쪽 다이어그램은 내가 의도한 바가 맞지만 오른쪽은 뭔지 모르겠다.
(+1 질문소재)
- Users 테이블에 Email, Password, Name 컬럼 생성하기
- 검증 규칙 설정하기
- 이메일 중복 여부 check, 형식 검증
- 비밀번호 8자 이상 조건 check
→ 위 두 항목은 Entity 설정에서 작성 완료- BCrypt 암호화하기
- POST 경로
("/api/auth/signup")로 설정하기
Spring Security를 추가하고 차근차근 Service와 Controller를 작성해나갔다.
API Test 결과
성공!
- 로그인 성공 시 Access Token + Refresh Token을 발급하기
- 이후 모든 API 요청에 활용하기?
일단 아래와 같이 Access Token과 Refresh Token을 생성하고 Access Token만 response에 저장하도록 했다.
//user 로그인
@Transactional
public LoginResponse login(LoginRequest request, HttpServletResponse response) {
String userEmail = request.getEmail();
String password = request.getPassword();
//사용자가 존재하는지 확인
User user = userRepository.findByEmail(userEmail).orElseThrow(
() -> new IllegalArgumentException("등록된 이메일이 없습니다."));
// 비밀번호 맞는지 확인
if (!passwordEncoder.matches(password, user.getPassword())) {
throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
}
// JWT 생성 및 쿠키에 저장 후 Response 객체에 추가
String accessToken = jwtUtil.createToken(user.getEmail(), ACCESS_TOKEN_TIME);
String refreshToken = jwtUtil.createToken(user.getEmail(), REFRESH_TOKEN_TIME);
jwtUtil.addJwtToCookie(accessToken, response);
return new LoginResponse(accessToken, refreshToken);
}
거의 강의 내용을 따라한거나 마찬가지라 아직 미숙해보인다...
API Test 결과
(트러블슈팅이 있었으나)결국 성공!
API Test 결과
성공!
로그인 API 구현 후 테스트를 진행했는데 아무리 봐도 같은 이메일 문자열인데 내가 입력한 문자열이 등록된 문자열이랑 다르다면서 콘솔 창에 IllegalArgumentException '등록되지 않은 이메일입니다.' 예외처리 메시지가 떴다.
가설 1. ddl-auto 설정을 create로 해서? ❌
서버를 시작할 때마다 테이블이 재생성되어서 못 찾는 건가 의심했다.
그래서 application.properties에서 MySQL url도 다시 점검해보고 ddl-auto 설정도 update로 변경해줬다.
→ 아~무 변화도 없었다. 문제는 여전했고...머리 세가닥은 빠졌다.
원인을 찾기 위해 일부러 다시 요청을 보내고, 콘솔창에 뜨는 SQL(Hibernate) 내용을 확인했다.
Hibernate:
select:
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.modified_at,
u1_0.name,
u1_0.password
from
users u1_0
where
u1_0.email is null
보이는가...? 마지막 줄
이거 왜 Null인 컬럼을 조회하고 있어???
가설 2. 잘못된 비교 대상을 가져왔다 ⭕
Request DTO
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class LoginRequest { private String userEmail; private String password; }
Response DTO
@Getter @AllArgsConstructor public class LoginResponse { private final String accessToken; private final String refreshToken; }
DB에 등록된 이메일의 컬럼명은 'email'
로그인할 때 제출받은 JSON 키 이름도 'email'
근데 JPA가 매핑해야 하는 DTO 필드명은 'userEmail' ... . . . .
같은 이름이 아니니 당연히 정확한 email 값을 못 가져왔던 것이다. (원인)
(참고용 ⬇️)
Service 로직
//user 로그인 @Transactional public LoginResponse login(LoginRequest request, HttpServletResponse response) { String userEmail = request.getEmail(); String password = request.getPassword(); //사용자가 존재하는지 확인 User user = userRepository.findByEmail(userEmail).orElseThrow( () -> new IllegalArgumentException("등록된 이메일이 없습니다.")); // 비밀번호 맞는지 확인 if (!passwordEncoder.matches(password, user.getPassword())) { throw new IllegalArgumentException("비밀번호가 일치하지 않습니다."); } // JWT 생성 및 쿠키에 저장 후 Response 객체에 추가 String accessToken = jwtUtil.createToken(user.getEmail(), ACCESS_TOKEN_TIME); String refreshToken = jwtUtil.createToken(user.getEmail(), REFRESH_TOKEN_TIME); jwtUtil.addJwtToCookie(accessToken, response); return new LoginResponse(accessToken, refreshToken); }
굉장히 어이없는 해결 방법...Postman을 껐다 켜자!
이전 요청이 너무 쌓였던건지 수정수정을 반복하다가 아무리 해도 동작 로딩이 계속 걸리더라. 열받아서 끄고 잠시 쉬다가 와서 다시 해봤는데? 멀쩡히 잘 돌아가더라😬