[Tistory] 세션을 사용해서 이메일 인증 - 서버

yuzu sim's avatar
Sep 23, 2024
[Tistory] 세션을 사용해서 이메일 인증 - 서버

1. 유저 테이블 - 이메일 인증여부

notion image
💡
이걸 넣었는데… 세션에서 빼서 쓰면 이거 필요 없음
 

2. UserRequest - JoinDTO

@Data public static class JoinDTO { private String username; private String password; private String email; private Boolean isEmailConfirmed; public User toEntity() { return User.builder() .username(username) .password(password) .email(email) .build(); } }
 

3. UserService - 이메일 인증 Random 숫자 생성

매번 더해가며 문자열을 생성했으나, StringBuilder를 사용함으로써 더 효율적으로 문자열을 생성
Random random = new Random(); int randomNumb; String randomNumStr = ""; for (int i = 0; i < 6; i++) { // 0부터 9까지 randomNumb = random.nextInt(10); randomNumStr = randomNumStr + randomNumb; } System.out.println("randomNumStr = " + randomNumStr);
notion image
💡
문자열로 저장해야함

3-1. UserService - 이메일 인증 Random 숫자 생성 수정 코드

StringBuilder 는 자동으로 생성된 랜덤 숫자를 문자열로 저장시킴
//이메일인증 public String mailCheck(String email) { String subject = "[Tistroy 회원가입 인증메일입니다]"; Random random = new Random(); StringBuilder code = new StringBuilder(); // 6자리 랜덤 숫자 생성 for (int i = 0; i < 6; i++) { int randomNum = random.nextInt(10); // 0부터 9까지 랜덤 숫자 생성 code.append(randomNum); // 숫자 추가 } System.out.println("Generated Code: " + code); // 생성된 코드 출력 // 이메일로 인증 코드 전송 String body = "귀하의 인증 코드는 " + code + "입니다."; emailUtil.sendEmail(email, subject, body); return code.toString(); // 최종 랜덤 코드 반환 }
  • 숫자를 문자열로 변환 후 저장: code.append(randomNum)을 사용하면 int형 숫자 randomNum이 자동으로 String으로 변환되어 StringBuilder에 추가되고 append() 메소드는 내부적으로 숫자를 문자열로 변환하는 과정을 처리한다.
  • 최종 문자열 생성: 마지막에 code.toString()을 호출하면, StringBuilder에 저장된 모든 값을 하나의 String으로 변환해 반환한다.
 

4. UserController - 세션사용

💡
세션에 담아서 비교하면 join버튼을 눌렀을 때, 서비스까지 갈 필요 없이 컨트롤러에서 막는다
//회원가입 @PostMapping("/join") public ResponseEntity<ApiUtil<Integer>> join(@ModelAttribute UserRequest.JoinDTO reqDTO, HttpSession session) { // 이메일 인증 여부 확인 if (reqDTO.getIsEmailConfirmed() == null || !reqDTO.getIsEmailConfirmed()) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(new ApiUtil<>(HttpStatus.BAD_REQUEST.value(), "이메일 인증이 필요합니다.")); } else { // 회원가입 로직 실행 User sessionUser = userService.join(reqDTO); if (sessionUser == null) { System.out.println("회원가입 실패: sessionUser가 null입니다."); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(new ApiUtil<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "회원가입에 실패했습니다.")); } // 세션에 사용자 정보 저장 session.setAttribute("sessionUser", sessionUser); System.out.println("세션 설정 완료: " + sessionUser); // 디버깅 로그 // 로그인 후 메인 페이지로 리다이렉트 확인 return ResponseEntity.ok(new ApiUtil<>(200)); } } //이메일 인증번호 보내는 메소드 @GetMapping("/send-mail") public ResponseEntity<?> sendMail(String email) { String emailCode = userService.mailCheck(email); System.out.println("email =" + email); // System.out.println("Generated emailCode = " + emailCode); session.setAttribute("emailCode", emailCode); return ResponseEntity.ok(new ApiUtil<>(emailCode)); } // 이메일 인증번호 일치 여부 확인 메소드 @GetMapping("/check-email-code") public ResponseEntity<?> checkEmailCode(String emailCode) { String sessionEmailCode = (String) session.getAttribute("emailCode"); // 로그 출력 System.out.println("Session Email Code: " + sessionEmailCode); System.out.println("User Input Email Code: " + emailCode); if (sessionEmailCode == null) { return ResponseEntity.ok(new ApiUtil<>(false)); } if (sessionEmailCode.equals(emailCode)) { return ResponseEntity.ok(new ApiUtil<>(true)); } else { return ResponseEntity.ok(new ApiUtil<>(false)); } }

5. 인증 모달창 화면 수정

notion image
notion image

 

4. input 이벤트는 특수문자 사용 불가

<!-- 이메일 주소 보내기 --> $("#email").on("input", function () { console.log($(this).val()); let email = $(this).val();
💡
처음엔 이렇게 input 이벤트를 줬는데…
notion image
notion image
💡
특수문자 때문에 터진다
 

5. 이메일 주소로 메일 보내기 encodeURIComponent() 함수를 사용

<div class="email-container"> <input class="my_auth_form_box_input" id="email" type="email" name="email" placeholder="이메일" maxlength="60" value="ssar1@nate.com" required/> button class="btn btn-outline-success btn-sm" type="submit" onclick="emailCheck()">인증하기</button> </div> <!-- 이메일 주소로 메일 보내기 --> function emailSendCode() { //console.log($("#email").val()); let email = encodeURIComponent($("#email").val()); $.ajax({ url: '/send-mail?email=' + email, type: 'GET' }).done((res) => { console.log("Response:", res); emailCode = res.body; console.log("Received code:", emailCode); showModal(); }).fail((res) => { alert("오류"); }); } }
notion image
💡
이제 script쪽에서는 잘 넘어가는데…
notion image
💡
서버에서 @ 같은 특수 문자를 처리하면서 문제가 발생 (@가 인코딩 되면서 %40로…)

HTML URL Encoding

notion image
💡
이메일 주소가 유효하지 않고 (없는 메일을 넣었으니…) RFC 5321 표준을 준수하지 않았다는 에러 창

5-1. 이메일 주소로 메일 보내기 해결 - 디코딩 필요XXX

  • 특수 문자 때문에 디코딩해서 넘겨야 하지만 StringBuilder 를 썼기 때문에 encodeURIComponent()로 인코딩된 값을 서버에서 받았을 때, 일반적으로 StringBuilder나 다른 문자열 관련 처리에서는 자동으로 디코딩할 필요가 없다. (하지만 이는 서버에서 어떻게 처리되는지에 따라 달라진다.)

상황 설명

  1. 클라이언트 측:
      • 클라이언트에서 encodeURIComponent()로 인코딩된 이메일 주소가 AJAX 요청으로 전송됩니다.
      • 이메일 주소는 특수 문자가 포함될 수 있기 때문에 인코딩된 상태로 URL에 포함됩니다.
  1. 서버 측:
      • 서버에서는 URL 파라미터(?email=encodedEmail)를 받을 때, 일반적으로 파라미터 값이 자동으로 디코딩된다.
      • 즉, 인코딩된 이메일 주소(user%40example%2Ecom)는 서버에서 받을 때 원래의 형태인 user@example.com으로 디코딩되어 처리된다.
       

notion image

6. mail이 들어온다.

notion image
 
Share article

Coding_study