Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat : mail authentication add #86

Merged
merged 31 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
dbebc52
build : mail library add
LeeJeongGi Apr 4, 2024
c555672
chore : mail config update
LeeJeongGi Apr 4, 2024
2484449
dev : email req dto create
LeeJeongGi Apr 8, 2024
dbc8839
dev : email res dto create
LeeJeongGi Apr 8, 2024
506562a
dev : email send service dev
LeeJeongGi Apr 8, 2024
a0da952
dev : email send controller dev
LeeJeongGi Apr 8, 2024
178ee53
dev : random number create
LeeJeongGi Apr 8, 2024
8d7ee23
dev : random number create
LeeJeongGi Apr 8, 2024
0b827b0
test : main send test code add
LeeJeongGi Apr 8, 2024
8bed1bf
test : mail send controller test
LeeJeongGi Apr 10, 2024
b5ab1e8
chore : code formatting
LeeJeongGi Apr 10, 2024
29c34b8
chore : not use class(sessionData) delete
LeeJeongGi Apr 10, 2024
ad8eb42
chore : Password delete
LeeJeongGi Apr 10, 2024
23dd94c
chore : email filed validation add
LeeJeongGi Apr 10, 2024
d4552da
dev : email code certification dto create
LeeJeongGi Apr 10, 2024
b7222c4
chore : code space 2 -> 4 modify, email certification button add
LeeJeongGi Apr 10, 2024
564a749
dev : session info save dto create
LeeJeongGi Apr 10, 2024
4696525
dev : code certification api create
LeeJeongGi Apr 10, 2024
66fb927
test : Test for error occurrence if email format is not valid
LeeJeongGi Apr 11, 2024
1973b96
chore : mail password add
LeeJeongGi Apr 11, 2024
31ba2c0
Merge branch 'develop' into feature/mail-authentication
ghkdqhrbals Apr 12, 2024
813dd59
chore : add jacocoTest exclusion class
LeeJeongGi Apr 13, 2024
317afb9
Merge remote-tracking branch 'origin/feature/mail-authentication' int…
LeeJeongGi Apr 13, 2024
b40d221
dev : Add email body generation factory class
LeeJeongGi Apr 13, 2024
f826eed
chore : factory param add
LeeJeongGi Apr 13, 2024
e2cd9a9
chore : test code modify
LeeJeongGi Apr 13, 2024
5e4495b
test : add various email certification code tests
LeeJeongGi Apr 13, 2024
5eef4dd
test : Error Test Temporary Comments
LeeJeongGi Apr 13, 2024
41c4f41
chore : strategy package move to common package
LeeJeongGi Apr 13, 2024
d36b661
chore : service 클래스 검증 제외(어떤 코드를 더 추가해야 할지 모르겠음,,,,,:()
LeeJeongGi Apr 13, 2024
ac6d451
chore : agent consts test code exception
LeeJeongGi Apr 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bm-agent/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ version = '1.0.0'

def excludeJacocoTestCoverageReport = [
// bmagent
'org/benchmarker/bmagent/consts/**',
'org/benchmarker/bmagent/BmAgentApplication**',
'org/benchmarker/bmagent/sse/**',
'org/benchmarker/bmagent/consts/SystemSchedulerConst',
Expand Down
4 changes: 3 additions & 1 deletion bm-controller/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ testlogger {

// define exclude classes for Jacoco test coverage report
def excludeJacocoTestCoverageReport = [
'org/benchmarker/bmcontroller/mail/service/**',
'org/benchmarker/bmcontroller/mail/common/**',
'org/benchmarker/bmcontroller/home/**',
'org/benchmarker/bmcontroller/template/**',
'org/benchmarker/bmcontroller/prerun/**',
Expand Down Expand Up @@ -105,10 +107,10 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client'
implementation 'org.springframework.boot:spring-boot-starter-mail' //mail
implementation 'org.webjars:webjars-locator-core'
implementation 'org.webjars:chartjs:2.9.3'


implementation 'org.springframework.boot:spring-boot-starter-validation'
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.benchmarker.bmcontroller.common.beans;

import org.benchmarker.bmcontroller.mail.common.strategy.IRandomCodeGenerator;
import org.benchmarker.bmcontroller.mail.common.strategy.RandomCodeGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RandomNumberConfig {
@Bean
public IRandomCodeGenerator randomNumber() {
return new RandomCodeGenerator();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.benchmarker.bmcontroller.mail.common.factory;

public interface EmailBodyGenerator {

String createBody(String... args);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.benchmarker.bmcontroller.mail.common.factory;

public class EmailVerificationFactory implements EmailBodyGenerator {

@Override
public String createBody(String... args) {

String authNum = args[0];

return "안녕하세요!\n\n, 회원 가입을 위한 인증 코드를 안내드립니다. 아래의 인증 코드를 입력하여 계정을 활성화하세요:\n\n인증 코드: " + authNum;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.benchmarker.bmcontroller.mail.common.strategy;

public interface IRandomCodeGenerator {

String generateVerificationCode();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.benchmarker.bmcontroller.mail.common.strategy;

import java.util.Random;

public class RandomCodeGenerator implements IRandomCodeGenerator {

private static final int CODE_LENGTH = 6;

@Override
public String generateVerificationCode() {

Random random = new Random();
StringBuilder codeBuilder = new StringBuilder();
for (int i = 0; i < CODE_LENGTH; i++) {
codeBuilder.append(random.nextInt(10));
}

return codeBuilder.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.benchmarker.bmcontroller.mail.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.benchmarker.bmcontroller.mail.common.factory.EmailBodyGenerator;
import org.benchmarker.bmcontroller.mail.common.factory.EmailVerificationFactory;
import org.benchmarker.bmcontroller.mail.controller.dto.*;
import org.benchmarker.bmcontroller.mail.service.IMailSender;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Objects;

@Slf4j
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class MailController {

private final IMailSender mailSender;

@PostMapping("/mail/certification")
public ResponseEntity<EmailResDto> mailSend(HttpServletRequest request,
@Valid @RequestBody EmailCertificationDto emailCertification) {

EmailBodyGenerator emailBodyGenerator = new EmailVerificationFactory();
EmailResDto mailResDto = mailSender.sendMail(emailCertification, emailBodyGenerator);

HttpSession session = request.getSession();

UserSessionInfo userSessionInfo = UserSessionInfo.builder()
.certificationCode(mailResDto.getCertificationCode())
.userMail(mailResDto.getMail())
.isVerification(false)
.verificationTime(LocalDateTime.now())
.build();

session.setAttribute("userSessionInfo", userSessionInfo);

log.info("Session data: {}", session.getAttribute("userSessionInfo").toString());

return ResponseEntity.ok(mailResDto);
}

@PostMapping("/mail/certification/code")
public ResponseEntity<EmailCodeCertificationResultDto> certificationCode(HttpServletRequest request,
@Valid @RequestBody EmailCodeDto emailCode) {

HttpSession session = request.getSession();
UserSessionInfo userSessionInfo = (UserSessionInfo) session.getAttribute("userSessionInfo");

// 세션에 userSessionInfo가 존재하지 않을 때
if (userSessionInfo == null) {

EmailCodeCertificationResultDto failRes = EmailCodeCertificationResultDto.builder()
.status("fail")
.message("Session expired or invalid. Please try again.")
.build();

return ResponseEntity.ok(failRes);
} else {
if (!userSessionInfo.verificationCode(emailCode.getCode())) {

EmailCodeCertificationResultDto failRes = EmailCodeCertificationResultDto.builder()
.status("fail")
.message("Please enter the authentication number correctly")
.build();

return ResponseEntity.ok(failRes);
}
}

EmailCodeCertificationResultDto successRes = EmailCodeCertificationResultDto.builder()
.status("success")
.message("Authentication successful!!")
.build();

Objects.requireNonNull(userSessionInfo).changeStatus();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 상단에서 userSessionInfo 의 null 체크를 진행되어있지만, 한번 더 체크해주셔서 좋네요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 몰라서,,,, 2차 트랩을 설치 했습니다 ㅎㅎ

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다ㅎㅎ

session.setAttribute("userSessionInfo", userSessionInfo);

return ResponseEntity.ok(successRes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.benchmarker.bmcontroller.mail.controller.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;


@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmailCertificationDto {

@NotBlank
@Pattern(regexp = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", message = "Please write in email format")
private String email;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.benchmarker.bmcontroller.mail.controller.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmailCodeCertificationResultDto {

private String status;

private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.benchmarker.bmcontroller.mail.controller.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;


@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmailCodeDto {

@NotBlank
private String code;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.benchmarker.bmcontroller.mail.controller.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmailResDto {

private String mail;

private String certificationCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.benchmarker.bmcontroller.mail.controller.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserSessionInfo {

private String certificationCode;

private String userMail;

private boolean isVerification;

private LocalDateTime verificationTime;

private LocalDateTime updateTime;

public boolean verificationCode(String code) {
return this.certificationCode.equals(code);
}

public void changeStatus() {
this.isVerification = !this.isVerification;
this.updateTime = LocalDateTime.now();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isVerification 을 false -> true 로 설정해주는 것 외 true -> false 로도 설정하기 위해서 위와 같이 로직을 구현한걸까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금은 false -> true 설정만 필요하긴 한데 true -> false 설정이 필요한 일이 생길 수도 있지 않을까 해서 설정했습니다!!

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.benchmarker.bmcontroller.mail.service;

import org.benchmarker.bmcontroller.mail.common.factory.EmailBodyGenerator;
import org.benchmarker.bmcontroller.mail.controller.dto.EmailCertificationDto;
import org.benchmarker.bmcontroller.mail.controller.dto.EmailResDto;

public interface IMailSender {

EmailResDto sendMail(EmailCertificationDto emailCertificationDto, EmailBodyGenerator emailBodyGenerator);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.benchmarker.bmcontroller.mail.service.impl;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.benchmarker.bmcontroller.mail.common.factory.EmailBodyGenerator;
import org.benchmarker.bmcontroller.mail.controller.dto.EmailCertificationDto;
import org.benchmarker.bmcontroller.mail.controller.dto.EmailResDto;
import org.benchmarker.bmcontroller.mail.service.IMailSender;
import org.benchmarker.bmcontroller.mail.common.strategy.IRandomCodeGenerator;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class MailSenderImpl implements IMailSender {

private final JavaMailSender javaMailSender;

private final IRandomCodeGenerator randomNumber;

@Override
public EmailResDto sendMail(EmailCertificationDto emailCertificationDto, EmailBodyGenerator emailBodyGenerator) {
String authNum = randomNumber.generateVerificationCode();

String subject = "회원 가입 인증 코드";
String body = emailBodyGenerator.createBody(authNum);

log.info("Start mail sender!!");
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, false, "UTF-8");
mimeMessageHelper.setTo(emailCertificationDto.getEmail()); // 메일 수신자
mimeMessageHelper.setSubject(subject); // 메일 제목
mimeMessageHelper.setText(body, false); // 메일 본문 내용, HTML 여부

javaMailSender.send(mimeMessage);

} catch (MessagingException e) {
log.info("Mail sender fail!!");
throw new RuntimeException(e);
}

return EmailResDto.builder()
.mail(emailCertificationDto.getEmail())
.certificationCode(authNum)
.build();
}

}
11 changes: 11 additions & 0 deletions bm-controller/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ spring:
jdbc:
time_zone: UTC
batch_size: 50
mail:
host: smtp.gmail.com
port: 587
username: 'apple4rhk'
password: 'rdndiwbefqkbvnau'
properties:
mail:
debug: true
smtp.auth: true
smtp.timeout: 50000
smtp.starttls.enable: true
data:
redis:
host: localhost
Expand Down
Loading
Loading