그 전에 했던 프로젝트 내용은 회원가입 페이지에서 단순히 이메일을 입력해서 회원가입을 진행했으나 본인 인증 수단으로 사용할 수 있는 이메일 인증을 구현해보고 싶었다.
그래서 이번에는 이메일 인증을 통해 보안을 강화하는 기능 업데이트를 해보려고 한다.
📧이메일 인증 방법
1️⃣
인증번호 입력
2️⃣
링크 클릭
업데이트 내용
🚩Before ➡️ 단순 이메일 입력
🚩After ➡️ 인증번호를 받아 이메일 인증
메일 인증을 위한 라이브러리를 pom.xml
에 추가한다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.5.4</version>
</dependency>
버전을 직접 적어도 되지만
<version>${org.springframework-version}</version>
은
자동으로 버전을 맞춰주기 때문에 더 편리하다.
원래 보안 수준이 낮은 앱의 액세스 허용 설정으로 이메일 인증을 할 수 있었는데 현재는 해당 서비스가 종료됐다.
2단계 인증을 활성화하고 앱 비밀번호를 생성해야 하고,
이 비밀번호는 지메일 비밀번호 대신 사용해야 하기에 꼭 필요한 과정이다.
여기서 잠시! 앱 비밀번호 설정을 하지 않고 일반 비밀번호 입력시 발생하는 오류이다.
이렇게 유저의 이름과 패스워드가 오류나서 메일을 보낼 수 없다고 뜬다.
16자리 앱 비밀번호가 생성된다.
2가지 경우가 있는데 1번 방식을 이용하려고 한다.
root-context.xml
에 이메일 인증 관련 설정을 위해 bean을 등록한다.
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="587" />
<property name="username" value="구글 계정@gmail.com" />
<property name="password" value="비밀번호 대신 앱키 입력" />
<property name="javaMailProperties">
<props>
<prop key="mail.transport.protocol">smtp</prop>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.debug">true</prop>
<prop key="mail.smtp.ssl.trust">smtp.gmail.com</prop>
<prop key="mail.smtp.ssl.protocols">TLSv1.2</prop>
</props>
</property>
</bean>
이메일 관련 기본 설정이 끝났다.
본격적으로 코드를 작성해보자.
메일로 인증번호 전송
var code = ""; /*인증번호 저장할 곳*/
$('#auth_btn').click(function() {
var email = $('#email').val(); /*입력한 이메일*/
console.log('완성된 이메일 : ' + email); /* 이메일 오는지 확인*/
var checkInput = $('.mail-check-input') /* 인증번호 입력 */
$.ajax({
type: 'GET',
url: 'mailCheck?email=' + email, /*url을 통해 데이터를 보낼 수 있도록 GET방식, url명을 "mailCheck"로 지정 */
success: function(data) {
console.log("data : " + data);
checkInput.attr('disabled', false); /*데이터가 성공적으로 들어오면 인증번호 입력란이 활성화되도록*/
code = data;
alert('인증번호가 전송되었습니다.')
},
}
);
jsp파일의 id/class를 지정한 이름을 이용해 각각 이메일, 인증번호 변수를 만들고 인증하기 버튼을 클릭하면 ajax를 통해 get방식으로 메일이 전송되도록 했다.
이때 인증 전에는 인증번호 입력란이 비활성화 되어 입력할 수 없는 상태이지만
데이터가 성공적으로 들어온다면(메일로 인증번호가 제대로 전송된다면)
번호 입력란은 활성화되어 입력 가능한 상태가 된다.
@Autowired
private JavaMailSender mailSender;
의존성 주입을 사용을 위해 @Autowired 을 적고
JavaMailSender 객체 타입인 mailSender 변수를 선언한다.
@RequestMapping(value = "member/mailCheck", method = RequestMethod.GET )
@ResponseBody
public String mailCheck(String email) throws Exception{ //반환값이 있기에 메서드 타입도 String
System.out.println("이메일 데이터 전송 확인"); //확인용
System.out.println("인증 이메일 : " + email);
//인증번호 생성
Random random = new Random();
int checkNum = random.nextInt(888888) + 111111;
System.out.println("인증번호 :"+ checkNum);
//이메일 전송 내용
String setFrom = "@gmail.com"; //발신 이메일
String toMail = email; //받는 이메일
String title = "KeepingBox 회원가입 인증 이메일 입니다.";
String content =
"인증 번호는 " + checkNum + "입니다." +
"해당 인증번호를 인증번호 확인란에 기입하여 주세요.";
//이메일 전송 코드
try {
MimeMessage message = mailSender.createMimeMessage();
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();
}
String num = Integer.toString(checkNum); // ajax를 뷰로 반환시 데이터 타입은 String 타입만 가능
return num; // String 타입으로 변환 후 반환
}
}
ajax코드가 실행되면 지정한 controller코드가 실행되는데 json통신을 하기위해
무조건 ❗❗❗ @ResponseBody을 써준다.
Random 객체로 난수를 생성해 6자리 숫자의 인증번호를 만들고 이메일 내용을 String 변수에 담아 작성한다.
그 다음 MimeMessage를 이용해 이메일을 전송할 코드를 작성한다.
return으로 받아 생성된 인증번호가 잘 넘어오는지 확인했다.
이메일 전송이 성공하면 console창에 메세지가 뜨고 jsp페이지에도 성공메세지가 alert로 뜬다.
이제 네이버 메일이 잘 왔는지 확인해보자!
오오!! 메세지가 정상적으로 보내졌다. 🎉🎉
이메일에 전송돼 발급받은 인증번호를 인증번호란에 입력하면
인증여부를 거쳐 일치할 경우 성공 문구와 함께 입력란이 파란색으로 바뀌고, 불일치할 경우 실패 문구와 함께 입력란이 빨간색으로 변경된다.
제이쿼리 문법을 사용했다.
$('.mail-check-input').on('input',function() {
var inputCode = $(".mail-check-input").val(); /*사용자가 입력한 전송 번호*/
var checkResult = $("#mail-check-input-info"); /* 비교 결과 */
if (inputCode == code) { // 일치할 경우
checkResult.html("인증번호가 일치합니다.");
checkResult.attr("class", "correct");
$(".mail-check-input").css("border","1.5px solid #3781E3");/*일치할 경우 테두리 색 변경*/
$(".mail-check-input").css("color","#3781E3");/*일치할 경우 글자 색 변경*/
} else {
checkResult.html("인증번호를 다시 확인해주세요.");
checkResult.attr("class", "incorrect");
$(".mail-check-input").css("border","1.5px solid red");
$(".mail-check-input").css("color","red");
}
});
사용자 입력란과 비교될 div영역을 각 변수로 지정하고
사용자가 입력한 전송 코드가 발급된 인증번호와 일치할 경우 결과 영역에는 성공 문구와 함께 input 테두리 색이 변경된다.
불일치할 경우에는 실패 문구와 함께 역시 input 테두리 색이 변경된다.