-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[FEAT]: 이메일 인증 과정을 통한 회원가입
- Loading branch information
Showing
19 changed files
with
418 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
src/main/java/mvp/deplog/infrastructure/mail/MailConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package mvp.deplog.infrastructure.mail; | ||
|
||
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 mailServerHost; | ||
|
||
@Value("${spring.mail.port}") | ||
private int mailServerPort; | ||
|
||
@Value("${spring.mail.username}") | ||
private String mailServerUsername; | ||
|
||
@Value("${spring.mail.password}") | ||
private String mailServerPassword; | ||
|
||
@Value("${spring.mail.properties.mail.debug}") | ||
private boolean mailDebug; | ||
|
||
@Value("${spring.mail.properties.mail.smtp.auth}") | ||
private boolean auth; | ||
|
||
@Value("${spring.mail.properties.mail.smtp.starttls.enable}") | ||
private boolean starttlsEnable; | ||
|
||
@Value("${spring.mail.properties.mail.smtp.starttls.required}") | ||
private boolean starttlsRequired; | ||
|
||
@Value("${spring.mail.properties.mail.smtp.ssl.enable}") | ||
private boolean sslEnable; | ||
|
||
@Bean | ||
public JavaMailSender javaMailSender() { | ||
JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); | ||
mailSender.setHost(mailServerHost); | ||
mailSender.setPort(mailServerPort); | ||
mailSender.setUsername(mailServerUsername); | ||
mailSender.setPassword(mailServerPassword); | ||
mailSender.setJavaMailProperties(getMailProperties()); | ||
|
||
return mailSender; | ||
} | ||
|
||
private Properties getMailProperties() { | ||
Properties properties = new Properties(); | ||
properties.put("mail.transport.protocol", "smtp"); | ||
properties.put("mail.debug", mailDebug); | ||
properties.put("mail.smtp.auth", auth); | ||
properties.put("mail.smtp.starttls.enable", starttlsEnable); | ||
properties.put("mail.smtp.starttls.required", starttlsRequired); | ||
properties.put("mail.smtp.ssl.enable", sslEnable); | ||
|
||
return properties; | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
src/main/java/mvp/deplog/infrastructure/mail/MailUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package mvp.deplog.infrastructure.mail; | ||
|
||
import jakarta.mail.MessagingException; | ||
import jakarta.mail.internet.MimeMessage; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.mail.javamail.JavaMailSender; | ||
import org.springframework.mail.javamail.MimeMessageHelper; | ||
import org.springframework.stereotype.Component; | ||
import org.thymeleaf.context.Context; | ||
import org.thymeleaf.spring6.SpringTemplateEngine; | ||
|
||
import java.security.SecureRandom; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class MailUtil { | ||
|
||
private final String SUBJECT = "Deplog 인증 링크입니다."; | ||
private final String SENDER_NAME = "DEPlog"; | ||
|
||
@Value("${spring.mail.username}") | ||
private String fromEmail; | ||
|
||
@Value("${example.verify.url}") | ||
private String verificationUrl; | ||
|
||
@Value("${example.verify.verification.email}") | ||
private String templateUrl; | ||
|
||
private final JavaMailSender mailSender; | ||
private final SpringTemplateEngine templateEngine; | ||
|
||
public MimeMessage createMessage(String code, String email) throws MessagingException { | ||
MimeMessage mimeMessage = mailSender.createMimeMessage(); | ||
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8"); | ||
helper.setTo(email); | ||
helper.setSubject(SUBJECT); | ||
helper.setFrom(fromEmail); | ||
helper.setText(setContext(code), true); // 'true' indicates HTML content | ||
|
||
return mimeMessage; | ||
} | ||
|
||
// Description : 코드 생성 함수 (00000000 ~ zzzzzzzz) (8자리) | ||
public String generateCode() { | ||
SecureRandom random = new SecureRandom(); | ||
// nextLong(long bound) : 0(포함)부터 입력된 bound(미포함) 사이의 랜덤 정수를 반환 | ||
long randomNumber = random.nextLong(2821109907455L + 1); | ||
String code = Long.toString(randomNumber, 36); | ||
code = String.format("%8s", code).replace(' ', '0'); | ||
|
||
return code; | ||
} | ||
|
||
// 타임리프를 이용한 context 설정 | ||
public String setContext(String code) { | ||
Context context = new Context(); | ||
context.setVariable("code", code); | ||
context.setVariable("verificationUrl", verificationUrl); | ||
return templateEngine.process(templateUrl, context); | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/main/java/mvp/deplog/infrastructure/mail/application/MailService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package mvp.deplog.infrastructure.mail.application; | ||
|
||
import jakarta.mail.internet.MimeMessage; | ||
import lombok.RequiredArgsConstructor; | ||
import mvp.deplog.domain.member.domain.repository.MemberRepository; | ||
import mvp.deplog.global.common.SuccessResponse; | ||
import mvp.deplog.infrastructure.mail.dto.MailCodeRes; | ||
import mvp.deplog.infrastructure.mail.MailUtil; | ||
import mvp.deplog.infrastructure.redis.RedisUtil; | ||
import org.springframework.mail.javamail.JavaMailSender; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.thymeleaf.spring6.SpringTemplateEngine; | ||
|
||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
@Service | ||
public class MailService { | ||
|
||
private final String VERIFY_SUFFIX = "_verify"; | ||
|
||
private final JavaMailSender mailSender; | ||
private final SpringTemplateEngine templateEngine; | ||
private final RedisUtil redisUtil; | ||
private final MailUtil mailUtil; | ||
|
||
private final MemberRepository memberRepository; | ||
|
||
public SuccessResponse<MailCodeRes> sendMail(String email) throws Exception { | ||
if (memberRepository.existsByEmail(email)) | ||
throw new IllegalArgumentException("이미 가입된 이메일입니다."); | ||
String code = mailUtil.generateCode(); | ||
redisUtil.setDataExpire(code, email, 60 * 3L); | ||
|
||
MimeMessage mimeMessage = mailUtil.createMessage(code, email); | ||
mailSender.send(mimeMessage); | ||
|
||
MailCodeRes mailCodeRes = MailCodeRes.builder() | ||
.code(code) | ||
.build(); | ||
|
||
return SuccessResponse.of(mailCodeRes); | ||
} | ||
|
||
public void verifyCode(String code) { | ||
String email = redisUtil.getData(code); | ||
if (email == null) | ||
throw new IllegalArgumentException("유효하지 않은 코드입니다."); | ||
redisUtil.deleteData(code); | ||
redisUtil.setDataExpire(email + VERIFY_SUFFIX, String.valueOf(true), 60 * 60L); | ||
|
||
// Message message = Message.builder() | ||
// .message("이메일 인증이 완료되었습니다.") | ||
// .build(); | ||
// | ||
// return SuccessResponse.of(message); | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/mvp/deplog/infrastructure/mail/dto/MailCodeRes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package mvp.deplog.infrastructure.mail.dto; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
|
||
@Data | ||
@Builder | ||
public class MailCodeRes { | ||
|
||
@Schema(type = "string", example = "abcd1234", description = "인증 코드를 출력합니다. 이메일 인증 시 사용자에게 발급되는 임시 키 값입니다.") | ||
private String code; | ||
} |
59 changes: 59 additions & 0 deletions
59
src/main/java/mvp/deplog/infrastructure/mail/presentation/MailApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package mvp.deplog.infrastructure.mail.presentation; | ||
|
||
import io.swagger.v3.oas.annotations.Hidden; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import mvp.deplog.global.common.Message; | ||
import mvp.deplog.global.common.SuccessResponse; | ||
import mvp.deplog.global.exception.ErrorResponse; | ||
import mvp.deplog.infrastructure.mail.dto.MailCodeRes; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.servlet.view.RedirectView; | ||
|
||
import java.io.IOException; | ||
|
||
@Tag(name = "Mail API", description = "메일 관련 API입니다.") | ||
public interface MailApi { | ||
|
||
@Operation(summary = "메일 발송 API", description = "메일을 발송합니다.") | ||
@ApiResponses(value = { | ||
@ApiResponse( | ||
responseCode = "200", description = "메일 발송 성공", | ||
content = {@Content(mediaType = "application/json", schema = @Schema(implementation = MailCodeRes.class))} | ||
), | ||
@ApiResponse( | ||
responseCode = "400", description = "메일 발송 실패", | ||
content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))} | ||
) | ||
}) | ||
@GetMapping | ||
ResponseEntity<SuccessResponse<MailCodeRes>> sendMail( | ||
@Parameter(description = "이메일을 입력해주세요.", required = true) @RequestParam String email | ||
) throws Exception; | ||
|
||
@Hidden | ||
@Operation(summary = "메일 검증 API", description = "메일을 검증합니다. 사용자가 링크 클릭 시 호출됩니다.") | ||
@ApiResponses(value = { | ||
@ApiResponse( | ||
responseCode = "200", description = "메일 검증 성공", | ||
content = {@Content(mediaType = "application/json", schema = @Schema(implementation = Message.class))} | ||
), | ||
@ApiResponse( | ||
responseCode = "400", description = "메일 검증 실패", | ||
content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))} | ||
) | ||
}) | ||
@GetMapping(value = "/verify") | ||
void verify( | ||
@Parameter(description = "메일 발송 시 응답받은 코드를 사용해주세요.", required = true) @RequestParam String code, | ||
HttpServletResponse response | ||
) throws IOException; | ||
} |
Oops, something went wrong.