웹 서비스의 가장 기본인 회원가입과 로그인을 구현하면서 이메일로 인증번호를 전송하여 인증하는 서비스를 구현해보았습니다.
spring:
mail:
host: smtp.gmail.com
port: 587
username: 전송할 구글 이메일
password: ${MAIL_PASSWORD}
properties:
mail:
smtp:
auth: true
starttls:
enable: true
깃허브 액션을 돌릴 때 적용할 수 있는 환경변수를 시크릿을 통해 등록할 수 있다.
깃허브 레포지토리 - Settings - Security - Secrets and variables - Actions에서 New Repository secret 클릭 후 키와 값을 입력
워크플로우 파일에서 아래와 같이 설정
env: // env 섹션
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
build-args: | // build-args 섹션
MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}
- name: Set environment variables for Docker Compose
run: | // run 단계
echo "MAIL_PASSWORD=${{ env.MAIL_PASSWORD }}" >> .env
💡 주의할 점 💡
처음에는 이메일도 환경변수로 등록해서 사용하려 했다. 하지만 계속 로그인이 되지 않는 에러 발생... 혹시나 하고 이메일을 명시했더니..성공
예측 : 깃허브 시크릿은 특수문자를 인식하지 못한다!
결론 : 이메일은 명시할 수 밖에 없다..
@MyLog
@PostMapping("/login/send")
public ResponseEntity<?> sendPasswordChangeCode(@RequestBody @Valid UserRequest.SendCodeInDTO sendCodeInDTO, Errors errors){
UserResponse.SendCodeOutDTO sendCodeOutDTO = userService.sendPasswordChangeCodeService(sendCodeInDTO);
ResponseDTO<?> responseDTO = new ResponseDTO<>(sendCodeOutDTO);
return ResponseEntity.ok().body(responseDTO);
}
@MyLog
@PostMapping("/signup/send")
public ResponseEntity<?> sendSignupCode(@RequestBody @Valid UserRequest.SendCodeInDTO sendCodeInDTO, Errors errors){
UserResponse.SendCodeOutDTO sendCodeOutDTO = userService.sendSignupCodeService(sendCodeInDTO);
ResponseDTO<?> responseDTO = new ResponseDTO<>(sendCodeOutDTO);
return ResponseEntity.ok().body(responseDTO);
}
public UserResponse.SendCodeOutDTO sendPasswordChangeCodeService(UserRequest.SendCodeInDTO sendCodeInDTO){
User userPS = findValidUserByEmail(sendCodeInDTO.getEmail());
if(!userPS.getFirstName().equals(sendCodeInDTO.getFirstName()) || !userPS.getLastName().equals(sendCodeInDTO.getLastName())){
throw new Exception400("name", "잘못된 요청입니다. ");
}
userPS.generateEmailCheckToken();
String html = createPasswordChangeHTML(userPS);
ClassPathResource imageResource = new ClassPathResource("static/logo.jpg");
try {
MailHandler mailHandler = new MailHandler(javaMailSender);
mailHandler.setTo(sendCodeInDTO.getEmail());
mailHandler.setSubject("3D 에셋 스토어, 비밀번호 재설정을 위한 이메일 인증");
mailHandler.setText(html, true);
mailHandler.setInline("logo", imageResource);
mailHandler.send();
} catch (Exception e) {
throw new Exception500("이메일 전송 실패 : " + e.getMessage());
}
return new UserResponse.SendCodeOutDTO(userPS.getId());
}
@Transactional
public UserResponse.SendCodeOutDTO sendSignupCodeService(UserRequest.SendCodeInDTO sendCodeInDTO) {
String html = createSignupHTML(user);
ClassPathResource imageResource = new ClassPathResource("static/logo.jpg");
try {
MailHandler mailHandler = new MailHandler(javaMailSender);
mailHandler.setTo(sendCodeInDTO.getEmail());
mailHandler.setSubject("3D 에셋 스토어, 회원가입을 위한 이메일 인증");
mailHandler.setText(html, true);
mailHandler.setInline("logo", imageResource);
mailHandler.send();
} catch (Exception e) {
throw new Exception500("이메일 전송 실패 : " + e.getMessage());
}
return new UserResponse.SendCodeOutDTO(user.getId());
}
// 회원가입 메일 본문 생성 메서드
private String createPasswordChangeHTML(User user){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy년 mm월 dd일 HH시 mm분 ss초");
LocalDateTime expiredTime = user.getEmailCheckTokenCreatedAt().plusMinutes(10);
String expiredTimeStr = expiredTime.format(formatter);
return "<body>\n" +
" <table\n" +
" style=\"\n" +
" background-color: #ffffff;\n" +
" width: 630px;\n" +
" height: 572px;\n" +
" padding: 5%;\n" +
" \"\n" +
" >\n" +
" <tr>\n" +
" <td style=\"text-align: center;\">\n" +
" <img src='cid:logo' style='width: 225px; height: 54px;' />"+
" <hr\n" +
" style=\"\n" +
" width: 100%;\n" +
" height: 1px;\n" +
" background-color: #9fadbc;\n" +
" margin: 32px 0 32px 0;\n" +
" \"\n" +
" />\n" +
" <div style=\"height: 358px; width: 566px;\">\n" +
" <h1>Neuroid Asset 비밀번호 재설정 인증</h1>\n" +
" <p>안녕하세요. Neuroid Asset Store입니다!</p>\n" +
" <p>\n" +
" 아래 인증 코드를 입력하면 비밀번호 재설정을 하실 수 있습니다.\n" +
" </p>\n" +
" <h2>인증 코드: [" + user.getEmailCheckToken()+ "]</h2>\n" +
" <strong\n" +
" >인증 코드는 대소문자를 구분합니다. 정확히 입력해 주세요.</strong\n" +
" >\n" +
" <p>\n" +
" 인증메일의 유효기간 내에 인증이 완료되지 않으면 인증이 취소됩니다.\n" +
" </p>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </body>";
}