일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 웹개발
- 정보처리기사
- 형변환
- 정보처리기사필기요약
- scanner
- 자바
- DML
- 프로그래밍
- 알고리즘
- Git
- order by
- Linux
- 데이터 조회
- select
- 프론트엔드
- Java
- StringBuilder
- html
- 예외처리
- sql문
- String클래스
- 백준
- where
- 리눅스
- 개발자
- 자바스크립트
- 클래스
- BufferedReader
- mybatis
- 메서드
- 스프링
- SQL
- MySQL
- 입출력
- 프로그래머스 sql 고득점 kit
- 백엔드
- select문
- github
- JavaScript
- 프로그래머스 SQL
- Today
- Total
ToBe끝판왕
[ JAVA ] 임시 비밀번호 발급 + 메일 전송 본문
■ 임시 비밀번호 발급 로직 생각해 보기
1) 사용자 ( 클라이언트 ) 가 아이디와 이메일주소를 입력 후 임시 비밀번호 발급 요청
2) 서버 ( Controller단 ) 에서 아이디와 이메일주소를 받아 Service 클래스로 전달
3) Service 클래스 ( 비즈니스 로직 )
- 사용자 DB 조회 ( 아이디와 이메일 )
- 임시 비밀번호 생성
- 생성된 비밀번호 암호화 하여 DB 저장
- 이메일로 임시 비밀번호 발송
4) 사용자 ( 클라이어트 ) 해당 임시 비밀번호로 로그인
5) 사용자 ( 클라이어트 ) 로그인 이후, 마이페이지에서 추후 사용할 비밀번호로 변경
JavaMailSender
■ JavaMailSender
- SpringFramework 에서 이메일을 간편하게 발송할 수 있도록 도와주는 인터페이스
- JavaMailSender 설정이 필요하다. ( 필자는 Config 클래스 + application.properties 설정을 하였다. )
- 의존성 주입 ( build.gradle )
// build.gradle 파일 안 dependencies {} 블록안에 아래 내용 삽입
// JavaMailSender 인터페이스 의존성 주입
implementation 'org.springframework.boot:spring-boot-starter-mail'
- MailConfig 클래스 생성
• SMTP 서버 사용을 위한 설정 ( Host , Port , username : 이메일 주소 , password : 앱 비밀번호 ) 세팅
• 일반적으로 Gmail 을 사용할 경우, host = smtp.gmail.com , port = 587 을 사용
package com.wsd.invest.user.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import java.util.Properties;
@Configuration
public class MailConfig {
@Value("${spring.mail.host}")
private String host;
@Value("${spring.mail.port}")
private int port;
@Value("${spring.mail.username}")
private String username;
@Value("${spring.mail.password}")
private String password;
@Bean
public JavaMailSender javaMailSender() {
// JavaMailSenderImpl 클래스를 이용하여 이메일 전송을 위한 객체 생성
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
// SMTP Server 설정
// Google SMTP Server 주소
mailSender.setHost(host);
// Google SMTP Port 넘버
mailSender.setPort(port);
// 인증 정보 설정
// 실제 사용할 gmail 주소
mailSender.setUsername(username);
// gmail 비밀번호
mailSender.setPassword(password);
// 추가 설정
Properties props = mailSender.getJavaMailProperties();
// SMTP 전송 프로토콜 사용 명시
props.put("mail.transport.protocol", "smtp");
// SMTP 인증 사용 명시
props.put("mail.smtp.auth", "true");
// TLS 시작 연결 사용 설정 (보안)
props.put("mail.smtp.starttls.enable", "true");
// 디버그 로그 활성화
props.put("mail.debug", "true");
return mailSender;
}
}
- application.properties 설정
# SMTP 서버 GOOGLE 설정
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=이메일주소
spring.mail.password=앱비밀번호
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.debug=true
※ Gmail 앱 비밀번호는 어떻게 생성 하나요 ?
• 아래 링크에 들어가서 본인 구글로 로그인을 하면 16자리의 앱 비밀번호를 수령 가능하다.
https://myaccount.google.com/apppasswords
- 코드 작성
• JSP 양식 페이지에서 회원이 본인의 Id 와 Email 주소를 입력 후, 전송 버튼
• 입력받은 Id 와 Email 주소를 통해 가입이 된 회원인지 조회
• 로그인 / 회원가입 기능이 SpringSecurity를 사용중이므로 임시 비밀번호를 생성하여 암호화
• 기존 회원의 비밀번호를 암호화된 비밀번호로 업데이트
• 입력받은 이메일 주소로 회원에게 메일 발송 ( 암호화 되기 이전의 임시 비밀번호 전송 )
- DTO 클래스 생성
• JSP 입력 폼에서 유효성 검사도 진행하기 위해 따로 Dto 클래스 파일 생성
• 앞단의 js 로 유효성 검사 + 뒷단의 @Valid 를 통한 유효성 검사를 진행한다.
package com.wsd.invest.user.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class FindPwDto {
@NotBlank(message = "아이디를 입력해주세요.")
private String memberId;
@NotBlank(message = "올바른 이메일 형식이 아닙니다.")
private String memberMail;
}
- Controller 클래스 내 메서드 생성
• @Valid 어노테이션 + BindingResult 를 통한 유효성 검증 ( JSP input 값 유효성 검증 )
• 임시 비밀번호 이메일 발송
• 이메일 발송 성공 시, 성공 메시지 / 이메일 발송 실패 시, 비밀번호 찾기 페이지로 redirect
※ 검증 ( @Valid 어노테이션 + BindingResult )
• @Valid 어노테이션 : 검증할 객체의 필드에 제약조건 어노테이션들의 검증을 실시한다.
• @Valid 어노테이션은 하나의 객체 전체에 대해 정의된 제약조건들을 한꺼번에 검사
( 한 필드는 검증을 만족하고 한 필드는 검증을 만족하지 못하는 경우 에러 발생 )
• BindingResult : @Valid 어노테이션과 함께 사용하여 .hasErrors() 메서드를 통해 검증에 실패했는지 확인 가능
• BindingResult : @Valid 어노테이션이 붙은 객체 바로 뒤에 위치해야 한다.
※ RedirectAttributes
• RedircetAttributes 는 Spring MVC 에서 Redirect 시 플래시 메시지를 사용할때 자주 사용된다.
• addFalshAttribute 메서드 : Redirect 되는 페이지에서 한번만 사용할 수 있는 FalshAttribute를 추가
@PostMapping("/findPw")
public String findPassword(@Valid @ModelAttribute("pwDto")FindPwDto findPwDto, BindingResult bindingResult
, RedirectAttributes redirectAttributes ) throws Exception{
log.info("========== 비밀번호 찾기 기능(임시 이메일 발급) 진행 ==========");
// 유효성 검증
if(bindingResult.hasErrors()) {
log.info("errors={}", bindingResult);
return "member/loginForm";
}
// 임시 비밀번호 메일 발송
String resultMsg = userDetailService.findPassword(findPwDto);
if("SUCCESS".equals(resultMsg)) {
redirectAttributes.addFlashAttribute("message", "임시 비밀번호가 이메일로 발송되었습니다.");
return "redirect:/user/login";
} else {
redirectAttributes.addFlashAttribute("message", resultMsg);
return "redirect:/user/findPw";
}
- Service 클래스 생성
• input 으로 입력받은 회원ID , 회원Email 주소로 DB 에서 가입된 회원인지 조회 및 Null 처리
• 임시 비밀번호 생성 후, 암호화를 거쳐 DB 회원테이블 내 해당 회원ID 의 비밀번호 컬럼값을 Update
• 입력받은 회원 Email 주소로 이메일 발송
※ MessagingException
• JavaMailAPI 에서 이메일을 보내는 과정 중 발생할 수 있는 모든 예외를 나타내는 부모 클래스
• 주요 원인 : SMTP 서버 연결 실패 / 인증 실패 / 메일 형식 오류 / 네트워크 오류 등
※ MimeMessage
• MIME( Multipurpose Internet Mail Extensions ) 형식의 이메일 메시지를 나타내는 인터페이스
• 텍스트 , HTML , 첨부 파일 등 다양한 형식의 내용 포함 가능
• 헤더정보 ( From , To , Subject 등 ) 설정 가능
• javax.mal 패키지에서 제공
• MimeMessageHelper 는 MimeMessage 를 생성하고 설정하는데 사용되는 헬퍼 클래스
public String findPassword(FindPwDto findPwDto) throws Exception{
try {
// 사용자 검색
FindPwDto pwUser = userDetailMapper.findMailUser(findPwDto);
if( pwUser == null ) {
return "등록되지 않은 사용자입니다.";
}
// 임시 비밀번호 생성 및 DB 저장
String tempPw = PasswordUtil.makeTempPassword();
String encodedPw = passwordEncoder.encode(tempPw);
userDetailMapper.updatePassword(findPwDto.getMemberId(), encodedPw);
// 이메일 발송
sendEmail(findPwDto.getMemberMail(), tempPw);
return "SUCCESS";
} catch (MessagingException me) {
log.error("임시 비밀번호 발급 중 오류 발생: {}", me.getMessage(), me);
return "이메일 발송에 실패하였습니다, 잠시 후 다시 시도해주세요.";
} catch( DataAccessException dae ) {
log.error("데이터베이스 작업중 오류 발생: {}", dae.getMessage(), dae);
return "시스템 오류가 발생하였습니다. 잠시 후 다시 시도해주시길 바랍니다.";
} catch(Exception e ) {
log.error("시스템 오류 발생: {}", e.getMessage(), e);
return "시스템 오류가 발생하였습니다. 잠시 후 다시 시도해주시길 바랍니다.";
}
}
private void sendEmail(String memberMail, String tempPw) throws MessagingException {
String emailContent = getEmailContent(tempPw);
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(memberMail);
helper.setSubject("StockLand 임시 비밀번호 발급 안내");
helper.setText(emailContent, true);
javaMailSender.send(message);
log.info("이메일 발송이 성공적으로 전송되었습니다. 이메일 주소:{}", memberMail);
}
private String getEmailContent(String tempPw) {
return "<p>안녕하세요,</p>" +
"<p>요청하신 임시 비밀번호는 아래와 같습니다.</p>" +
"<p><strong>" + tempPw + "</strong></p>" +
"<p>로그인 후 마이페이지에서 비밀번호를 변경해 주세요.</p>";
}
※ 필자의 경우 Login 양식 JSP 에 비밀번호 입력칸의 유효성검사가 8~15자의 영어 대소문자 + 숫자 + 특수문자가
되어있어, 임시비밀번호를 해당 유효성 검사 규칙에 맞게 생성 하기 위해 PasswordUtil 클래스를 생성하였다.
package com.wsd.invest.util;
import java.security.SecureRandom;
public class PasswordUtil {
public static String makeTempPassword() {
// 영어 대문자 상수 선언
final String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 영어 소문자 상수 선언
final String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
// 숫자 상수 선언
final String NUMBERS = "0123456789";
// 특수문자 상수 선언
final String SPECIAL_CHAR = "!@#$%^&*()-_+=<>?";
// 전체 문자열 상수 선언
final String ALL_CHARS = UPPERCASE + LOWERCASE + NUMBERS + SPECIAL_CHAR;
// 최소 길이 상수 선언
final int MIN_LENGTH = 8;
// 최대 길이 상수 선언
final int MAX_LENGTH = 15;
// 난수 생성기 객체
SecureRandom random = new SecureRandom();
// 문자열 생성 객체
StringBuilder sb = new StringBuilder();
// 영문 대/소문자 , 숫자, 특수문자 1자 랜덤 추가
sb.append(getRandomChar(UPPERCASE, random));
sb.append(getRandomChar(LOWERCASE, random));
sb.append(getRandomChar(NUMBERS, random));
sb.append(getRandomChar(SPECIAL_CHAR, random));
// 8~ 15 사이의 랜덤 길이 생성
int passwordLength = random.nextInt((MAX_LENGTH - MIN_LENGTH) + 1 ) + MIN_LENGTH;
// 나머지 글자는 랜덤하게 채움
// 총 길이 8~15자 중 적당한 길이로 생성
for (int i = 4; i < passwordLength; i++) {
sb.append(getRandomChar(ALL_CHARS, random));
}
// 비밀번호를 랜덤하게 섞음
return shuffleString(sb.toString(), random);
}
// 랜던 문자 메서드
private static String getRandomChar(String characters, SecureRandom random) {
// 문자열에서 랜덤한 1개의 문자를 가져온다.
return String.valueOf(characters.charAt(random.nextInt(characters.length())));
}
// 문자열 섞는 메서드
private static String shuffleString(String input, SecureRandom random) {
// 문자열을 char[] 배열로 변환
char[] characters = input.toCharArray();
for (int i = characters.length - 1; i > 0; i--) {
int j = random.nextInt(i + 1);
char temp = characters[i];
characters[i] = characters[j];
characters[j] = temp;
}
// char 배열을 다시 문자열로 변환
return new String(characters);
}
}
- 메일 발송
• Google SMTP 서버를 이용하여 Google 이메일 계정 -> 회원 Naver 계정으로 임시비밀번호 발급 진행
• 아래의 그림과 같이 정상적으로 임시비밀번호가 발급되어 보내진것을 알 수 있다.
▶ 다음에는 Spring 메일 발송을 사용하여 사용자 메일 인증 기능 또한 구현해봐야 겠다.
'■ 공부 기록 > 기능 구현' 카테고리의 다른 글
[ Swagger ] SpringBoot 3.x 환경 + Swagger 3 활용 API 테스트 (2) (0) | 2025.01.10 |
---|---|
[ Swagger ] SpringBoot 3.x 환경 + Swagger 3 이해 및 적용 (1) (0) | 2025.01.07 |
[ API ] 간단 Restful CRUD API 포스트맨 테스트 ( SpringBoot + Gradle + MyBatis + Mysql ) (1) | 2025.01.02 |
[ Poi 라이브러리 ] JAVA로 Excel 다운로드 기능 구현 (2) (0) | 2024.04.07 |
[ Poi 라이브러리 ] JAVA로 Excel 다운로드 기능 구현 (1) (0) | 2024.04.07 |