나의개발일지
새 비밀번호 생성 with. e-mail 본문
비밀번호를 잊어버리면 DB관리자도 암호화된 비밀번호를 알 수 없어서 새로운 비밀번호를 생성후 DB에 업데이트하고 메일로 발송 한다.
프로젝트를 시작하고, 로그인버튼을 클릭한후 find password 버튼을 눌러서 새로운 비밀번호 찾기 절차가 실행된다.
◆ 비밀번호 찾기 화면
◆ 메일 전송 완료
메일 발송 모듈 설정
스프링에서는 메일 발송을 위해 JavaMailSenderImpl을 이용한다.
JavaMailSenderImpl을 사용하기 위해 pom.xml과 Ioc컨테이너에 등록하는 과정이 필요하다.
<pom.xml>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<mail-context.xml>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<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="#생성된 앱 비밀번호"/>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
</beans>
<web.xml>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/jdbc-context.xml
/WEB-INF/spring/security-context.xml
/WEB-INF/spring/mail-context.xml
/WEB-INF/spring/file-context.xml
</param-value>
</context-param>
Gmail의 앱 비밀번호는 해당 포스트를 참고 바란다.
https://cacaodotori.tistory.com/22
Gmail 2단계 인증 및 앱 비밀번호 생성하기
앱 비밀번호는 일반적으로 Gmail 계정을 앱이나 디바이스에 연결할 때 사용된다. 특히 보안 앱 또는 이메일 클라이언트와 같은 앱에서 Gmail 계정을 사용할 때 필요하다. 1. 크롬에서 구글 계정으로
cacaodotori.tistory.com
비밀번호 찾기 메일 발송 과정 구현
1. JSP페이지
form태그를 이용해서 아이디와, 이름, 이메일정보를 받아서 버튼이 눌릴때 Cotroller에게 정보들과 "/admin/member/findPasswordConfirm" 신호를 전달한다.
※ 이때 post방식으로 전달한다.
<div class="find_password_form">
<form action="<c:url value='/admin/member/findPasswordConfirm' />" name="find_password_form" method="post">
<input type="text" name="a_m_id" placeholder="INPUT ADMIN ID."> <br>
<input type="text" name="a_m_name" placeholder="INPUT ADMIN NAME."> <br>
<input type="text" name="a_m_mail" placeholder="INPUT ADMIN MAIL."> <br>
<input type="button" value="find password" onclick="findPassword();">
<input type="reset" value="reset">
</form>
</div>
2. Controller
컨트롤러 부분에서 서비스에 있는 findPasswordConfirm을 호출하여 결과값에 저장후 다음으로 내보낼 페이지를 지정한다.
※ 호출할때 "adminMemberVo"가 사용된다.
@PostMapping("/findPasswordConfirm")
public String findPasswordConfirm(AdminMemberVo adminMemberVo) {
System.out.println("[AdminMemberController] findPasswordConfirm");
String nextPage = "admin/member/find_password_ok";
int result = adminMemberService.findPasswordConfirm(adminMemberVo);
if (result > 0)
nextPage = "admin/member/find_password_ng";
return nextPage;
}
3. Service
● findPasswordConfirm 메서드
- DAO에 selectAdmin메서드를 실행하여 해당 id, name, mail을 사용하여 유저정보를 받아온다.
- 만약 유저가 있으면 createPassword 메서드를 실행하여 새로운 비밀번호를 만든후
- DAO에 updatePassword 메서드를 실행하여 DB에 새로운 비밀번호로 바꾼다.
- 새로운 비밀번호를 메일로 발송 한다.
public int findPasswordConfirm(AdminMemberVo adminMemberVo) {
System.out.println("[AdminMemberService] findPasswordConfirm");
AdminMemberVo selectedAdminMemberVo = adminMemberDao.selectAdmin(adminMemberVo.getA_m_id(), adminMemberVo.getA_m_name(), adminMemberVo.getA_m_mail());
int result = 0;
if (selectedAdminMemberVo != null) {
//등록된 id이므로 새 비밀번호 생성
String newPassword = createPassword();
//데이터베이스에 업데이트
result = adminMemberDao.updatePassword(adminMemberVo.getA_m_id(),newPassword);
//새 비밀번호를 메일로 발송
sendNewPasswordByMail(adminMemberVo.getA_m_mail(), newPassword);
}
return result;
}
● createPassword 메서드
- 0 ~ 9 까지, a ~ z 까지 새로운 문자 배열 chars을 생성한다.
- 랜덤설정에 사용하는 Seed는 현재 시간이다.
- 비밀번호는 총 8자리이며 secureRandom을 이용하여 랜덤으로 새로운 비밀번호가 될 chars의 idx를 가져온다.
- 만약 idx가 짝수라면 stringBuffer에 toUpperCase()를 이용하여 대문자로 추가하고
- 홀수라면 소문자로 추가한다.
- 새로운 비밀번호를 출력후 리턴한다.
private String createPassword() {
System.out.println("[AdminMemberService] createPassword");
char[] chars = new char[] {'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','n','m','o','p','q','r','s','t','u','v','w','x','y','z'
};
StringBuffer stringBuffer = new StringBuffer();
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(new Date().getTime());
int index = 0;
int length = chars.length;
for (int i=0; i<8; i++) {
index = secureRandom.nextInt(length);
if(index%2 == 0)
stringBuffer.append(String.valueOf(chars[index]).toUpperCase());
else
stringBuffer.append(String.valueOf(chars[index]).toLowerCase());
}
System.out.println("NEW PASSWORD : " + stringBuffer.toString());
return stringBuffer.toString();
}
● sendNewPasswordByMail 메서드
- JavaMailSenderImpl을 사용하기위해 @Autowired를 사용하여 객체주입을 해야한다.
- 익명클래스를 사용하여 MimeMessagePreparator 인스턴스를 초기화 한다.
- (MimeMessagePreparator는 MIME 메시지를 준비하기 위한 콜백 인터페이스이다.)
- MIME메시지 전송을 간단화 시키는 helper 인스턴스를 초기화 한다.
- 수신자 메일, 제목, 내용(새로운 비밀번호)을 설정한다.
- send메서드를 이용하여 발송한다.
@Autowired
JavaMailSenderImpl javaMailSenderImpl;
//생략
private void sendNewPasswordByMail(String a_m_mail, String newPassword) {
final MimeMessagePreparator mimeMessagePreparator =
new MimeMessagePreparator() {
@Override
public void prepare(MimeMessage mimeMessage) throws Exception {
final MimeMessageHelper helper =
new MimeMessageHelper(mimeMessage, true, "utf-8");
helper.setTo(a_m_mail);
helper.setSubject("[한국 도서관] 새 비밀번호 발송");
helper.setText("새 비밀번호는 :" + newPassword, true);
}
};
javaMailSenderImpl.send(mimeMessagePreparator);
}
4. DAO
● selectAdmin 메서드
※여기서 전에 구현한 메서드에서 selectAdmin메서드가 있지만 매서드 오버로딩을 활용하였다.
id, name, mail값을 확인하여 유저정보를 DB에서 가져온다.
public AdminMemberVo selectAdmin(String a_m_id, String a_m_name, String a_m_mail) {
String sql = "SELECT * FROM tb1_admin_member WHERE a_m_id=? AND " +
"a_m_name=? AND a_m_mail=?";
List<AdminMemberVo> adminMemberVos = new ArrayList<AdminMemberVo>();
adminMemberVos = jdbcTemplate.query(sql, new RowMapper<AdminMemberVo>() {
@Override
public AdminMemberVo mapRow(ResultSet rs, int rowNum) throws SQLException {
AdminMemberVo adminMemberVo = new AdminMemberVo();
adminMemberVo.setA_m_no(rs.getInt("a_m_no"));
adminMemberVo.setA_m_approval(rs.getInt("a_m_approval"));
adminMemberVo.setA_m_id(rs.getString("a_m_id"));
adminMemberVo.setA_m_pw(rs.getString("a_m_pw"));
adminMemberVo.setA_m_name(rs.getString("a_m_name"));
adminMemberVo.setA_m_gender(rs.getString("a_m_gender"));
adminMemberVo.setA_m_part(rs.getString("a_m_part"));
adminMemberVo.setA_m_position(rs.getString("a_m_position"));
adminMemberVo.setA_m_mail(rs.getString("a_m_mail"));
adminMemberVo.setA_m_phone(rs.getString("a_m_phone"));
adminMemberVo.setA_m_reg_date(rs.getString("a_m_reg_date"));
adminMemberVo.setA_m_mod_date(rs.getString("a_m_mod_date"));
return adminMemberVo;
}
}, a_m_id, a_m_name, a_m_mail);
return (adminMemberVos.size() > 0)? adminMemberVos.get(0) : null;
}
● updatePassword 메서드
새롭게 받은 비밀번호를 passwordEncoder를 활용해 암호화하여 DB에 업데이트 한다.
public int updatePassword(String a_m_id, String newPassword) {
System.out.println("[AdminMemberDao] updatePassword(String a_m_id)");
String sql = "UPDATE tb1_admin_member SET a_m_pw = ?, a_m_mod_date = NOW() WHERE a_m_id = ?";
int result = -1;
result = jdbcTemplate.update(sql, passwordEncoder.encode(newPassword), a_m_id);
return result;
}