inblog logo
|
Coding_study
    Spring

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

    yuzu sim's avatar
    yuzu sim
    Sep 23, 2024
    [Tistory] 세션을 사용해서 이메일 인증 - 서버
    Contents
    1. 유저 테이블 - 이메일 인증여부2. UserRequest - JoinDTO 3. UserService - 이메일 인증 Random 숫자 생성3-1. UserService - 이메일 인증 Random 숫자 생성 수정 코드4. UserController - 세션사용5. 인증 모달창 화면 수정5-1. 이메일 주소로 메일 보내기 해결 - 디코딩 필요XXX6. mail이 들어온다.

    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

    W3Schools.com
    W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.
    W3Schools.com
    https://www.w3schools.com/tags/ref_urlencode.ASP
    W3Schools.com
    notion image
    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

    RSS·Powered by Inblog