[Spring] 이메일 인증 구현하기(feat. 네이버 메일)

우롱밀크티당도70·2023년 8월 14일
1

Spring

목록 보기
1/4
post-thumbnail
post-custom-banner

1. 배경

토이 프로젝트 진행 중 회원가입 페이지의 이메일 인증 기능이 필요해서 구현하게 됐다... 이메일 인증이 다음과 같은 순서로 진행된다.
1. input 태그에 이메일을 입력
2. 버튼을 통해 입력한 이메일로 인증번호 발송(Ajax)
3. 받은 인증번호를 인증번호 확인 input 태그에 작성
4. 입력한 인증번호와 이메일로 받은 인증번호가 같은지 체크
5. 같으면 회원가입 버튼 활성화, 다르면 회원가입 버튼 비활성화


2. 개발환경

  • Java 1.8
  • SpringFramework

3. 구현하기

3-1. 네이버 메일 POP3/SMTP 사용함으로 설정하기

  • 우선 사용할 네이버 메일의 환경 설정에서 POP3/SMTP 사용을 '사용함'으로 설정한 후 저장한다.

3-2. pom.xml에 의존성 주입하기

		<!-- 이메일 인증을 위한 API -->
		<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
		<dependency>
		    <groupId>javax.mail</groupId>
		    <artifactId>mail</artifactId>
		    <version>1.4.7</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-context-support</artifactId>
		    <version>5.3.9</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs -->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz-jobs</artifactId>
			<version>2.3.0</version>
		</dependency>
  • pom.xml에 작성을 마친 후 꼭 메이븐 프로젝트 업데이트 한다.
    Maven->Update Project(Alt + F5)

3-3. 스프링 설정 파일에 Bean 등록하기(root-context.xml)

	<!-- 이메일 인증 관련 등록 -->
	<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
		<property name="host" value="smtp.naver.com"/>
	    <property name="port" value="465"/>
	    <property name="username" value="(ID)"/>
	    <property name="password" value="(비밀번호)"/>
	    <!-- 보안연결 SSL과 관련된 설정 -->
	    <property name="javaMailProperties">
		    <props>
		      <prop key="mail.smtp.auth">true</prop>
		      <prop key="mail.smtp.starttls.enable">true</prop>
		      <prop key="mail.smtps.checkserveridentity">true</prop>
		      <prop key="mail.smtps.ssl.trust">*</prop>
		      <prop key="mail.debug">true</prop>
		      <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
		     </props>
	     </property>
	</bean>
  • username과 password의 value에는 사용할 자신의 네이버 ID와 비밀번호를 작성하면 된다.

3-4. 회원가입 페이지 UI 구성

  • 부트스트랩을 사용.
  • 인증하기 버튼을 누르기 전에는 인증 번호를 입력할 수 있는 input 태그가 비활성화 되어있는 상태이다.
  • html 코드는 이메일 인증과 구현에 필요한 부분만...
<div class="form-group">
  <input class="form-control" placeholder="이메일을 입력해주세요." name="email" id="email" type="email" autofocus>
    <div style="display: block; text-align: right;">
      <input type="button" value="인증하기" class="btn btn-primary" id="emailAuth">
    </div>
  <input class="form-control" placeholder="인증 코드 6자리를 입력해주세요." maxlength="6" disabled="disabled" name="authCode" id="authCode" type="text" autofocus>
  <span id="emailAuthWarn"></span>
</div>
<input type="submit" value="회원가입" class="btn btn-lg btn-success btn-block" id="registerBtn" disabled="disabled">
  • 이메일을 입력 받는 input 태그의 id : email
  • 인증받기 버튼 태그의 id : emailAuth
  • 인증 번호를 입력 받는 input 태그의 id : authCode
  • 입력한 인증 번호와 이메일로 받은 인증 번호가 일치하는지 여부를 보여주는 span 태그의 id : emailAuthWarn
  • 회원가입 submit input 태그의 id : registerBtn

3-5. Ajax를 이용한 비동기 방식으로 인증 번호 이메일 발송하기

  • 인증하기 버튼을 눌러 입력한 이메일로 인증 번호를 보내는 Script를 작성한다.
  • Jquery를 작성하기 전에 Jquery cdn을 추가했는지 확인하기...자주 까먹는다.
<script type="text/javascript">
	//인증하기 버튼을 눌렀을 때 동작
	$("#emailAuth").click(function() {
    	const email = $("#email").val(); //사용자가 입력한 이메일 값 얻어오기
    		
    	//Ajax로 전송
        $.ajax({
        	url : './EmailAuth',
        	data : {
        		email : email
        	},
        	type : 'POST',
        	dataType : 'json',
        	success : function(result) {
        		console.log("result : " + result);
        		$("#authCode").attr("disabled", false);
        		code = result;
        		alert("인증 코드가 입력하신 이메일로 전송 되었습니다.");
       		}
        }); //End Ajax
    });
<scirpt>
  • Ajax로 인증 번호 이메일 발송이 성공적으로 이루어졌다면 이메일을 전송했다는 alert을 띄우고 인증번호를 입력할 수 있는 input 태그가 활성화 된다.
  • result에 담긴 값을 code에 초기화.

3-6. Controller

  • 위에서 작성한 Ajax url 경로가 Controller와 매핑된다.
  • Controller에서는 6자리 난수를 생성하여 전달 받은 이메일 주소로 이메일을 보낸다.
  • createMimeMessage() 메소드를 사용하기 위해서 JavaMailSenderImpl에 @Autowired 어노테이션을 부여한다.
  • return 타입은 int.
	@Autowired
	JavaMailSenderImpl mailSender;

	//이메일 인증
	@PostMapping("/EmailAuth")
	@ResponseBody
	public int emailAuth(String email) {
		
		log.info("전달 받은 이메일 주소 : " + email);
		
		//난수의 범위 111111 ~ 999999 (6자리 난수)
		Random random = new Random();
		int checkNum = random.nextInt(888888)+111111;
		
		//이메일 보낼 양식
		String setFrom = "(ID@naver.com)"; //2단계 인증 x, 메일 설정에서 POP/IMAP 사용 설정에서 POP/SMTP 사용함으로 설정o
		String toMail = email;
		String title = "회원가입 인증 이메일 입니다.";
		String content = "인증 코드는 " + checkNum + " 입니다." +
						 "<br>" +
						 "해당 인증 코드를 인증 코드 확인란에 기입하여 주세요.";
		
		try {
			MimeMessage message = mailSender.createMimeMessage(); //Spring에서 제공하는 mail API
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
            helper.setFrom(setFrom);
            helper.setTo(toMail);
            helper.setSubject(title);
            helper.setText(content, true);
            mailSender.send(message);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		log.info("랜덤숫자 : " + checkNum);
		return checkNum;
	}
  • setFrom은 보내는 사람의 이메일(root-context.xml에서 입력한 계정의 이메일).
  • toMail은 사용자가 입력한 이메일.
  • title과 content는 메일 제목과 내용.

위의 내용을 진행했다면 아래의 사진과 같은 동작이 실행된다.

문제 없이 동작 되었다면 이메일 입력 칸에 작성한 이메일로 인증 번호 이메일이 도착해있다.

3-7. 전달 받은 인증 번호를 입력하여 일치 여부 확인하기

  • JavaScript로 인증 번호 입력 칸에 인증 번호를 입력 한 후 영역을 벗어났을 때 인증번호가 일치하는지 일치하지 않는지를 보여준다.
<script type="text/javascript">
	//인증 코드 비교
    $("#authCode").on("focusout", function() {
    	const inputCode = $("#authCode").val(); //인증번호 입력 칸에 작성한 내용 가져오기
    	
    	console.log("입력코드 : " + inputCode);
    	console.log("인증코드 : " + code);
    		
    	if(Number(inputCode) === code){
        	$("#emailAuthWarn").html('인증번호가 일치합니다.');
        	$("#emailAuthWarn").css('color', 'green');
    		$('#emailAuth').attr('disabled', true);
    		$('#email').attr('readonly', true);
    		$("#registerBtn").attr("disabled", false);
    	}else{
        	$("#emailAuthWarn").html('인증번호가 불일치 합니다. 다시 확인해주세요!');
        	$("#emailAuthWarn").css('color', 'red');
        	$("#registerBtn").attr("disabled", true);
    	}
    });
<script>
  • focusout은 요소가 포커스를 벗어났을 때 동작하는 이벤트이다.
  • if문으로 인증 번호 입력 칸에 작성한 내용과 전송된 메일에 적혀있던 인증 번호가 같은지 비교한다.
    - 이 때 인증 번호 입력 칸에 작성한 내용이 담겨있는 inputCode를 Number로 형변환 하여 비교한다.
    (Controller의 return 타입이 int형이기 때문에...)
  • 인증 번호가 일치하면 회원가입 버튼을 활성화 하고 일치하지 않으면 비활성화 한다.
    - Jquery의 .attr() 함수는 엘리먼트의 속성값을 가져오거나 변경할 수 있다.
  • 왼쪽-불일치 했을 경우 UI, 오른쪽-일치 했을 경우의 UI

4. 오류가 났을 때 확인해 볼 사항

org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted.

  • root-context.xml에 username과 password를 맞게 잘 입력했는데도 일치하지 않는다는 오류가 발생할 수 있다.
    이 때 본인의 네이버 계정이 2단계 인증 설정이 되어있지 않은지 확인해보아야 한다.(해제하면 해결된다.)

5. 생각해볼 점, 개선이 필요한 부분

  • 내 이메일이 아니라 발신 전용 이메일로 보낼 수 있는 방법이 있는지...
  • root-context.xml에 username과 password를 그대로 적어버리는 행위에 대한 개선이 필요하다.
profile
안뇽하세용
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 8월 14일

유익한 자료 감사합니다.

답글 달기