[Spring] 이메일 인증하기

Posted by 신희준 on December 4, 2017



2017 - 12 - 04 (월)


이메일 인증하기


계정 설정

Post Sample Image

1 . 위에서 보이는 이미지 처럼 보안수준이 낮은 앱 허용 을 해준다.

2 . 필요한 라이브러리 추가 ( pom.xml )

<!-- mail -->
<dependency>
	<groupId>javax.mail</groupId>
	<artifactId>mail</artifactId>
	<version>1.4.7</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
	<version>${org.springframework-version}</version>
</dependency>

3 . MailHandler를 만들어 준다.

package com.almom.common;

import java.io.UnsupportedEncodingException;

import javax.activation.DataSource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

public class MailHandler {

    private JavaMailSender mailSender;
    private MimeMessage message;
    private MimeMessageHelper messageHelper;

    public MailHandler(JavaMailSender mailSender) throws MessagingException {
        this.mailSender = mailSender;
        message = this.mailSender.createMimeMessage();
        messageHelper = new MimeMessageHelper(message, true, "UTF-8");
    }

    public void setSubject(String subject) throws MessagingException {
        messageHelper.setSubject(subject);
    }
    public void setText(String htmlContent) throws MessagingException {
        messageHelper.setText(htmlContent, true);
    }
    public void setFrom(String email, String name) throws UnsupportedEncodingException, MessagingException {
        messageHelper.setFrom(email, name);
    }
    public void setTo(String email) throws MessagingException {
        messageHelper.setTo(email);
    }
    public void addInline(String contentId, DataSource dataSource) throws MessagingException {
        messageHelper.addInline(contentId, dataSource);
    }
    public void send() {
        mailSender.send(message);
    }

}

4 . TempKey 작성 : 인증키를 생성해줄 것이다.

package com.almom.common;

import java.util.Random;

public class TempKey {

    private boolean lowerCheck;
    private int size;

    public String getKey(int size, boolean lowerCheck) {
        this.size = size;
        this.lowerCheck = lowerCheck;
        return init();
    }

    private String init() {
        Random ran = new Random();
        StringBuffer sb = new StringBuffer();
        int num = 0;
        do {
            num = ran.nextInt(75)+48;
            if((num>=48 && num<=57) || (num>=65 && num<=90) || (num>=97 && num<=122)) {
                sb.append((char)num);
            }else {
                continue;
            }
        } while (sb.length() < size);
        if(lowerCheck) {
            return sb.toString().toLowerCase();
        }
        return sb.toString();
    }

}

5 . root-context.xml 에 host 이메일 주소를 설정해준다.

<!-- 메일 보내기  -->
	<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="메일" />
		<property name="password" value="비번" />


	<!-- email 요청시는 SMTP -->
		<property name="javaMailProperties">
			<props>
				<prop key="mail.transport.protocol">smtp</prop>
				<prop key="mail.smtp.auth">true</prop>
				<prop key="mail.smtp.starttls.enable">true</prop>
				<prop key="mail.debug">true</prop>
			</props>
		</property>
	</bean>

6 . Controller 작성 : 회원 가입시 이메일 인증코드를 생성한다. 이 인증 코드는 후에 다른 컨트롤러에서 처리를 받아 회원 상태를 활성화 시킬 것이다. (/register 로 매핑되는 컨트롤러에서 등록한 ID는 authStatus[로그인 가능 유 무] 가 활성화 되지 않은 상태)

@RequestMapping(value = "/register", method = RequestMethod.POST)
public String RegisterPost(UserVO user, Model model, RedirectAttributes rttr, HttpServletRequest request, HttpSession session) throws Exception {
	logger.info("회원가입...");
	logger.info(user.toString());
	service.create(user);
	rttr.addFlashAttribute("authmsg" , "가입시 사용한 이메일로 인증해주 3");
	return "redirect:/";
}

7 . Service 작성 : 트랜잭션 컨트롤을 위해 root-context.xml 에 아래 코드 추가를 할 필요가 있다. (namespace 에 tx가 체크가 안되있을 경우 체크하고 maven update할 것) 병행제어를 하는 이유는 연쇄적인 복귀나 모순성 갱신내용 손실을 막기 위함이다. @Transactional 애너테이션을 활용하여 간단하게 하나의 서비스 내에서 두개의 DAO 를 처리한다.

<bean id = "transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name = "dataSource" ref = "dataSource"></property>
</bean>
<tx:annotation-driven/>
@Inject
private JavaMailSender mailSender;


@Transactional
@Override
public void create(UserVO vo) throws Exception {
dao.insertUser(vo); // 회원가입 DAO

String key = new TempKey().getKey(50, false); // 인증키 생성

dao.createAuthKey(vo.getUser_email(), key); // 인증키 DB저장

MailHandler sendMail = new MailHandler(mailSender);
sendMail.setSubject("[ALMOM 서비스 이메일 인증]");
sendMail.setText(
		new StringBuffer().append("<h1>메일인증</h1>").append("<a href='http://localhost/user/emailConfirm?user_email=").append(vo.getUser_email()).append("&key=").append(key).append("' target='_blenk'>이메일 인증 확인</a>").toString());
sendMail.setFrom("호스트 이메일 아이디", "알몸개발자");
sendMail.setTo(vo.getUser_email());
sendMail.send();
}

8 . DAO 생성 : 아래에는 mapper 이다.

@Override
public void insertUser(UserVO vo) throws Exception {
	// TODO Auto-generated method stub

	logger.info("dao "+vo);
	System.out.println("DAO 로그 : 회원가입 중");
	sqlSession.insert(namespace +".insertUser", vo);
//		System.out.println(vo.toString());
}

@Override
public void createAuthKey(String user_email, String user_authCode) throws Exception {
	// TODO Auto-generated method stub
	UserVO vo = new UserVO();
	vo.setUser_authCode(user_authCode);
	vo.setUser_email(user_email);

	sqlSession.selectOne(namespace + ".createAuthKey", vo);
}
<insert id = "insertUser">
insert into USER (user_email, user_password, user_name, user_snsId, user_sex, user_phoneNumber, user_birth)
values(#{user_email}, #{user_password}, #{user_name}, #{user_snsId} , #{user_sex}, #{user_phoneNumber}, #{user_birth})
</insert>

<update id="createAuthKey">
update USER set user_authCode = #{user_authCode} where user_email = #{user_email}
</update>

9 . 현재 까지 절차로 회원가입을 하게되면 DB에 회원정보는 저장되지만 user_authStatus 컬럼은 활성화 상태가 되지 않았다. 이를 활성화 시켜주기 위한 이메일 인증작업이 필요하다. 현재까지의 작업으로 회원가입할 때 사용한 이메일로 인증요청이 발송되었다.

10 . 사용자가 인증을 확인하였을 때 서버에서 요청받을 컨트롤러를 생성해준다.

@RequestMapping(value = "/emailConfirm", method = RequestMethod.GET)
public String emailConfirm(String user_email, Model model) throws Exception { // 이메일인증
	service.userAuth(user_email);
	model.addAttribute("user_email", user_email);

	return "/user/emailConfirm";
}

11 . 서비스 생성

	@Override
	public void userAuth(String userEmail) throws Exception {
		dao.userAuth(userEmail);
	}

12 . DAO 생성

@Override
public void userAuth(String user_email) throws Exception {
	// TODO Auto-generated method stub
	sqlSession.update(namespace + ".userAuth", user_email);
}

13 . jsp 생성

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<script type="text/javascript">
		var userEmail = '${user_email}';

		alert(userEmail + '님 회원가입을 축하합니다. 이제 로그인이 가능 합니다.');

		window.open('', '_self', ''); // 브라우저창 닫기
		/* window.close(); // 브라우저 창 닫기 */
		self.location = '/';
		</script>
</body>
</html>