![[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