![[Tistory] 세션을 사용해서 이메일 인증 - 서버](https://image.inblog.dev?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D%255BTistory%255D%2520%25EC%2584%25B8%25EC%2585%2598%25EC%259D%2584%2520%25EC%2582%25AC%25EC%259A%25A9%25ED%2595%25B4%25EC%2584%259C%2520%25EC%259D%25B4%25EB%25A9%2594%25EC%259D%25BC%2520%25EC%259D%25B8%25EC%25A6%259D%2520-%2520%25EC%2584%259C%25EB%25B2%2584%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3DCoding_study&w=2048&q=75)
1. 유저 테이블 - 이메일 인증여부

이걸 넣었는데… 세션에서 빼서 쓰면 이거 필요 없음
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);

문자열로 저장해야함
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. 인증 모달창 화면 수정


4. input 이벤트는 특수문자 사용 불가
<!-- 이메일 주소 보내기 --> $("#email").on("input", function () { console.log($(this).val()); let email = $(this).val();
처음엔 이렇게 input 이벤트를 줬는데…


특수문자 때문에 터진다
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("오류"); }); } }

이제 script쪽에서는 잘 넘어가는데…

서버에서 @ 같은 특수 문자를 처리하면서 문제가 발생 (@가 인코딩 되면서 %40로…)

이메일 주소가 유효하지 않고 (없는 메일을 넣었으니…)
RFC 5321 표준을 준수하지 않았다는 에러 창
5-1. 이메일 주소로 메일 보내기 해결 - 디코딩 필요XXX
- 특수 문자 때문에 디코딩해서 넘겨야 하지만 StringBuilder 를 썼기 때문에
encodeURIComponent()
로 인코딩된 값을 서버에서 받았을 때, 일반적으로StringBuilder
나 다른 문자열 관련 처리에서는 자동으로 디코딩할 필요가 없다. (하지만 이는 서버에서 어떻게 처리되는지에 따라 달라진다.)
상황 설명
- 클라이언트 측:
- 클라이언트에서
encodeURIComponent()
로 인코딩된 이메일 주소가 AJAX 요청으로 전송됩니다. - 이메일 주소는 특수 문자가 포함될 수 있기 때문에 인코딩된 상태로 URL에 포함됩니다.
- 서버 측:
- 서버에서는 URL 파라미터(
?email=encodedEmail
)를 받을 때, 일반적으로 파라미터 값이 자동으로 디코딩된다. - 즉, 인코딩된 이메일 주소(
user%40example%2Ecom
)는 서버에서 받을 때 원래의 형태인user@example.com
으로 디코딩되어 처리된다.

6. mail이 들어온다.

Share article