09009

[Spring] 예제 2 - 암호화, 메일인증 본문

Back-End/Spring
[Spring] 예제 2 - 암호화, 메일인증
09009

암호화 담당 클래스 생성

암호화 관련 메서드는 static으로 설계할 것이다.

package com.ja.finalproject.util;

import java.security.MessageDigest;

public class PasswordEncoder {
	public static String encoding(String value) {
		
		System.out.println("해싱 전 비밀번호 : " + value);
		
		String hashCode = null;
		
		//password hashing...
		try {
			// sha-1 방식으로 messageDigest 실행 (sha-1은 이제 잘 쓰지 않는다.)
			MessageDigest messageDigest = MessageDigest.getInstance("sha-1"); 
			messageDigest.reset();
			messageDigest.update(value.getBytes("UTF-8")); //해싱할 값 세팅..
			byte [] chars = messageDigest.digest(); //해싱 값... 도출...
			
			StringBuilder sb = new StringBuilder();
			for(int i = 0 ; i < chars.length ; i++) {
				String tmp = Integer.toHexString(chars[i] & 0xff);
				if(tmp.length() == 1) {
					sb.append("0");
				}
				sb.append(tmp);
			}
			
			hashCode = sb.toString();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("해싱 후 비밀번호 : " + hashCode);
		
		return hashCode; 
	}
}

 

✍ MemberServiceImpl

입력한 비밀번호가 insert되기 전에 암호화 작업이 처리되고 암호화 처리된 비밀번호를 DTO에 넣고

insert 한다.

		// insert 하기 전에 비밀번호 암호화
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
				
		memberSqlMapper.insert(memberDto);
	public void register(MemberDto memberDto, int[] hobby_id) {
		
		System.out.println("여기서 알고리즘 수행");
		
		int memberPk = memberSqlMapper.createPk(); // primary key 생성, nextval이 실행된다.
		
		// ! 중요 !
		memberDto.setId(memberPk); // 파라미터로 안받기 때문에 SET으로 해주어야함.
		
		// insert 하기 전에 비밀번호 암호화
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
				
		memberSqlMapper.insert(memberDto);
		
		if(hobby_id != null) {
			for(int hobbyId : hobby_id) {
				
				MemberHobbyDto memberHobbyDto = new MemberHobbyDto();
				memberHobbyDto.setHobby_id(hobbyId);
				memberHobbyDto.setMember_id(memberPk);
				
				memberSqlMapper.insertMemberHobby(memberHobbyDto);
			}
		}

	}

회원가입 시 비밀번호를 1111로 입력하고 데이터베이스를 확인하면

암호화 처리된 비밀번호가 나온다.

 

로그인 시 인코딩 처리도 해주어야 한다.

	// controller 쪽에서 있는지 없는지 판단해야하므로 리턴타입을 만든다.
	public MemberDto getMemberByIdAndPw(MemberDto memberDto) {
		
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
		
		
		MemberDto sessionUser =  memberSqlMapper.selectByUserIdAndPw(memberDto);
		// 데이터베이스에 select된 결과로서의 dto -> sessionUser
		return sessionUser;
	}

 


 

메일 인증

pom.xml에 메일 관련 라이브러리 추가

	<!-- Mail 관련 라이브러리 -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-context-support</artifactId>
		    <version>5.0.7.RELEASE</version>
		</dependency>
		
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>1.4.7</version>
		</dependency>

root-context.xml에 설정

username, password는 변경해야함.

password: 구글 웹 비밀번호

	<!-- 메일 전송 관련 라이브러리 세팅... -->
	<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="     @    .com" />
		<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">false</prop>
			<prop key="mail.smtp.ssl.trust">smtp.gmail.com</prop>
			<prop key="mail.smtp.ssl.protocols">TLSv1.2</prop>
		</props>
		</property>
	</bean>

MemberServiceImpl

논리적으로 해결이 안되는 문제는 try -catch 문을 사용하는 편이다.

	public void register(MemberDto memberDto, int[] hobby_id) {
		
		System.out.println("여기서 알고리즘 수행");
		
		int memberPk = memberSqlMapper.createPk(); // primary key 생성, nextval이 실행된다.
		
		// ! 중요 !
		memberDto.setId(memberPk); // 파라미터로 안받기 때문에 SET으로 해주어야함.
		
		// insert 하기 전에 비밀번호 암호화
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
				
		memberSqlMapper.insert(memberDto);
		
		if(hobby_id != null) {
			for(int hobbyId : hobby_id) {
				
				MemberHobbyDto memberHobbyDto = new MemberHobbyDto();
				memberHobbyDto.setHobby_id(hobbyId);
				memberHobbyDto.setMember_id(memberPk);
				
				memberSqlMapper.insertMemberHobby(memberHobbyDto);
			}
		}
		
		// 이메일 보내기
		try {
				MimeMessage mimeMessage = javaMailSender.createMimeMessage();
				MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
				
				// subject: 제목
				mimeMessageHelper .setSubject("제목 테스트!!!!!");
				mimeMessageHelper.setText("본문 테스트!!!!");
				
				mimeMessageHelper.setFrom("admin", "관리자");
				//누구한테 보낼 것인가? (받는 쪽)
				mimeMessageHelper.setTo("kindred09009@gmail.com");
				
				javaMailSender.send(mimeMessage);
			
				
				} catch (Exception e) {
					e.printStackTrace();
				}
				
	
			}

회원가입 수행하면 메일이 수신되었다.

 

메일 인증 테이블 설계

한 명의 회원이 이메일 인증을 여러 번 할 수 있다.

일대 다 관계

처음에는 인증완료시간이 없으므로 NULL값 허용해야함

	public void register(MemberDto memberDto, int[] hobby_id) {
		
		System.out.println("여기서 알고리즘 수행");
		
		int memberPk = memberSqlMapper.createPk(); // primary key 생성, nextval이 실행된다.
		
		// ! 중요 !
		memberDto.setId(memberPk); // 파라미터로 안받기 때문에 SET으로 해주어야함.
		
		// insert 하기 전에 비밀번호 암호화
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
				
		memberSqlMapper.insert(memberDto);
		
		if(hobby_id != null) {
			for(int hobbyId : hobby_id) {
				
				MemberHobbyDto memberHobbyDto = new MemberHobbyDto();
				memberHobbyDto.setHobby_id(hobbyId);
				memberHobbyDto.setMember_id(memberPk);
				
				memberSqlMapper.insertMemberHobby(memberHobbyDto);
			}
		}
		
		// 이메일 보내기
		try {
				MimeMessage mimeMessage = javaMailSender.createMimeMessage();
				MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
				
				// subject: 제목
				mimeMessageHelper .setSubject("FP 회원가입을 축하드립니다.");
				
				String mailAuthKey = UUID.randomUUID().toString();
				
				String text = mailAuthKey;
				
				mimeMessageHelper.setText(text);
				
				mimeMessageHelper.setFrom("admin", "관리자");
				//누구한테 보낼 것인가? (받는 쪽)
				mimeMessageHelper.setTo(memberDto.getEmail()); // 회원가입 시 작성한 이메일
				
				javaMailSender.send(mimeMessage);
	
				} catch (Exception e) {
					e.printStackTrace();
				}
				
	
			}

 

테이블 생성

DATE TABLE fp_mail_auth; 
 
-- 이메일 인증 T
CREATE TABLE fp_mail_auth(
  id NUMBER PRIMARY KEY,
  member_id NUMBER,
  key VARCHAR2(200),
  complete VARCHAR2(1),
  complete_date DATE
);  
 
DROP SEQUENCE fp_mail_auth_seq; 
CREATE SEQUENCE fp_mail_auth_seq;

 

DTO 생성

MailAuthDto

package com.ja.finalproject.dto;

import java.util.Date;

public class MailAuthDto {

	private int id;
	private int member_id;
	private String key;
	private String complete;
	private Date complete_date;
	public MailAuthDto() {
		super();
	}
	public MailAuthDto(int id, int member_id, String key, String complete, Date complete_date) {
		super();
		this.id = id;
		this.member_id = member_id;
		this.key = key;
		this.complete = complete;
		this.complete_date = complete_date;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getMember_id() {
		return member_id;
	}
	public void setMember_id(int member_id) {
		this.member_id = member_id;
	}
	public String getKey() {
		return key;
	}
	public void setKey(String key) {
		this.key = key;
	}
	public String getComplete() {
		return complete;
	}
	public void setComplete(String complete) {
		this.complete = complete;
	}
	public Date getComplete_date() {
		return complete_date;
	}
	public void setComplete_date(Date complete_date) {
		this.complete_date = complete_date;
	}	
}

 이제 회원가입할 때 3개의 테이블에 동시에 insert 될 것이다.

MemberSqlMapper

	// 메일 인증
	public void insertMailAuth(MailAuthDto mailAuthDto);
	public void updateCompleteYByKey(String key);

MemberSqlMapper.xml

	<insert id="insertMailAuth">
		INSERT INTO fp_mail_auth VALUES(
			fp_mail_auth_seq.nextval,
			#{member_id},
			#{key},
			'N',
			null
			)
	</insert>
	
	<update id="updateCompleteYByKey">
		UPDATE fp_mail_auth 
		SET
			complete = 'Y',
			complete_date = SYSDATE
		WHERE key = #{key}	
	</update>

MemberServiceImpl

		String mailAuthKey = UUID.randomUUID().toString();
		
		MailAuthDto mailAuthDto = new MailAuthDto();
		mailAuthDto.setMember_id(memberPk);
		mailAuthDto.setKey(mailAuthKey);
		memberSqlMapper.insertMailAuth(mailAuthDto);

코드 수정

	public void register(MemberDto memberDto, int[] hobby_id) {
		
		System.out.println("여기서 알고리즘 수행");
		
		int memberPk = memberSqlMapper.createPk(); // primary key 생성, nextval이 실행된다.
		
		// ! 중요 !
		memberDto.setId(memberPk); // 파라미터로 안받기 때문에 SET으로 해주어야함.
		
		// insert 하기 전에 비밀번호 암호화
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
				
		memberSqlMapper.insert(memberDto);
		
		if(hobby_id != null) {
			for(int hobbyId : hobby_id) {
				
				MemberHobbyDto memberHobbyDto = new MemberHobbyDto();
				memberHobbyDto.setHobby_id(hobbyId);
				memberHobbyDto.setMember_id(memberPk);
				
				memberSqlMapper.insertMemberHobby(memberHobbyDto);
			}
		}
		
		String mailAuthKey = UUID.randomUUID().toString();
		
		MailAuthDto mailAuthDto = new MailAuthDto();
		mailAuthDto.setMember_id(memberPk);
		mailAuthDto.setKey(mailAuthKey);
		memberSqlMapper.insertMailAuth(mailAuthDto);
		
		// 이메일 보내기
		try {
				MimeMessage mimeMessage = javaMailSender.createMimeMessage();
				MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
				
				// subject: 제목
				mimeMessageHelper .setSubject("FP 회원가입을 축하드립니다.");
				
				
				String text = "";
				text += "회원가입을 축하드립니다. <br>";
				text += "아래 링크를 클릭하셔서 인증을 완료하신 후 이용 가능합니다. <br>";
				text += "<a href='http://localhost:8181/finalproject/member/successMail?key="+mailAuthKey+"'>인증하기</a>";
				
				mimeMessageHelper.setText(text, true); // html로 날라간다.
				
				mimeMessageHelper.setFrom("admin", "관리자");
				//누구한테 보낼 것인가? (받는 쪽)
				mimeMessageHelper.setTo(memberDto.getEmail()); // 회원가입 시 작성한 이메일
				
				javaMailSender.send(mimeMessage);
	
				} catch (Exception e) {
					e.printStackTrace();
				}
				
	
			}

메서드 추가

	public void successMail(String key) {
		memberSqlMapper.updateCompleteYByKey(key);
	}

MemberController

	@RequestMapping("successMail")
	public String successMail(String key) {
		memberService.successMail(key);
		return "member/completeMailAuth";
	}

completeMailAuth.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	이메일 인증이 완료되었습니다. 로그인 후 이용 가능합니다. <br>
	<a href="../board/mainPage">메인 페이지</a>
	<a href="../member/loginPage">로그인</a>
</body>
</html>

로그인 쿼리 변경

memberSqlMapper.xml

	<!--  select는 꼭 result 타입을 세팅해주어야 한다. -->
	<select id="selectByUserIdAndPw" resultType="com.ja.finalproject.dto.MemberDto">
		SELECT fm.*
		FROM fp_member fm INNER JOIN fp_mail_auth fma ON fm.id = fma.member_id
		WHERE fm.user_id = #{user_id}
		AND fm.user_pw = #{user_pw}	
		AND fma.complete = 'Y'
	</select>

 loginFail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
로그인 실패, 아이디 혹은 비밀번호를 확인해주세요. 혹은 이메일 인증을 해야합니다. <br>
<a href="./loginPage">로그인 페이지로 이동</a>
</body>
</html>

 

회원가입 때 소요되는 시간이 길어지는 문제

- 병렬처리 : 쓰레드

쓰레드 클래스 생성

MemberServiceImpl

package com.ja.finalproject.member.service;

import java.util.List;
import java.util.UUID;

import javax.mail.internet.MimeMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import com.ja.finalproject.dto.HobbyCategoryDto;
import com.ja.finalproject.dto.MailAuthDto;
import com.ja.finalproject.dto.MemberDto;
import com.ja.finalproject.dto.MemberHobbyDto;
import com.ja.finalproject.member.mapper.MemberSqlMapper;
import com.ja.finalproject.util.PasswordEncoder;

@Service
public class MemberServiceImpl {
	
	@Autowired
	private MemberSqlMapper memberSqlMapper;

	@Autowired
	private JavaMailSender javaMailSender;
	
	public void register(MemberDto memberDto, int[] hobby_id) {
		
		System.out.println("여기서 알고리즘 수행");
		
		int memberPk = memberSqlMapper.createPk(); // primary key 생성, nextval이 실행된다.
		
		// ! 중요 !
		memberDto.setId(memberPk); // 파라미터로 안받기 때문에 SET으로 해주어야함.
		
		// insert 하기 전에 비밀번호 암호화
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
				
		memberSqlMapper.insert(memberDto);
		
		if(hobby_id != null) {
			for(int hobbyId : hobby_id) {
				
				MemberHobbyDto memberHobbyDto = new MemberHobbyDto();
				memberHobbyDto.setHobby_id(hobbyId);
				memberHobbyDto.setMember_id(memberPk);
				
				memberSqlMapper.insertMemberHobby(memberHobbyDto);
			}
		}
		
		String mailAuthKey = UUID.randomUUID().toString();
		
		MailAuthDto mailAuthDto = new MailAuthDto();
		mailAuthDto.setMember_id(memberPk);
		mailAuthDto.setKey(mailAuthKey);
		memberSqlMapper.insertMailAuth(mailAuthDto);
		
		// // 이메일 보내기 (쓰레드 처리)
		new MailSendThread(javaMailSender, memberDto.getEmail(), mailAuthKey).start();

				
	
			}
	
	// controller 쪽에서 있는지 없는지 판단해야하므로 리턴타입을 만든다.
	public MemberDto getMemberByIdAndPw(MemberDto memberDto) {
		
		String pw = memberDto.getUser_pw(); // pw = 입력된 패스워드
		pw = PasswordEncoder.encoding(pw); 
		memberDto.setUser_pw(pw); 
		
		
		MemberDto sessionUser =  memberSqlMapper.selectByUserIdAndPw(memberDto);
		// 데이터베이스에 select된 결과로서의 dto -> sessionUser
		return sessionUser;
	}
	
	public List<HobbyCategoryDto> getHobbyList() {
		return memberSqlMapper.selectHobbyList();
	}
	
	
	public void successMail(String key) {
		memberSqlMapper.updateCompleteYByKey(key);
	}

	
}

class MailSendThread extends Thread {
		
		private JavaMailSender javaMailSender;
		private String to;
		private String key;
		
		public MailSendThread(JavaMailSender javaMailSender, String to, String key) {
			super();
			this.javaMailSender = javaMailSender;
			this.to = to;
			this.key = key;
		}

		public void run() {

			try {
					MimeMessage mimeMessage = javaMailSender.createMimeMessage();
					MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
					
					// subject: 제목
					mimeMessageHelper .setSubject("FP 회원가입을 축하드립니다.");
					
					
					String text = "";
					text += "회원가입을 축하드립니다. <br>";
					text += "아래 링크를 클릭하셔서 인증을 완료하신 후 이용 가능합니다. <br>";
					text += "<a href='http://localhost:8181/finalproject/member/successMail?key="+key+"'>인증하기</a>";
					
					mimeMessageHelper.setText(text, true); // html로 날라간다.
					
					mimeMessageHelper.setFrom("admin", "관리자");
					//누구한테 보낼 것인가? (받는 쪽)
					mimeMessageHelper.setTo(to); // 회원가입 시 작성한 이메일
					
					javaMailSender.send(mimeMessage);
		
					} catch (Exception e) {
						e.printStackTrace();
					}
			
		}
 }

registerComplete.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	회원가입이 완료되었습니다. 메일인증 후 로그인 가능합니다. 메일을 확인하여 주시기 바랍니다.
	메일 전송은 3분정도 소요될 수 있습니다. <a href="./loginPage">로그인 페이지로</a>
</body>
</html>