Spring Boot - 메일 인증 구현하기

Hannah·2023년 2월 7일
0

kotlin-project

목록 보기
3/3
post-thumbnail

Code

Plugin

build.gradle.kts

dependencies {
    // ...

	// redis
    implementation ("org.springframework.boot:spring-boot-starter-data-redis")

    // mail
    implementation ("org.springframework.boot:spring-boot-starter-mail")
}
  • spring-boot-starter-data-redis : redis는 메일 인증 시간 계산 및 인증 번호를 위해 사용하였습니다.
  • spring-boot-starter-mail : 메일을 사용자에게 보내기 위해 사용하였습니다.

Controller

@RestController
@RequestMapping("/user-certification")
class UserMailController(
    private val userMailService: UserMailService
) {

    @NoToken
    @PostMapping("")
    fun memberCertification(@RequestBody request: CertificationRequest): Success<String> {
        userMailService.sendMail(request.email)
        return Success(SuccessCode.SUCCESS_SEND_MAIL)
    }

    @NoToken
    @PostMapping("/check")
    fun memberCheckCertification(@RequestBody request: CertificationCheckRequest): Success<String> {
        userMailService.checkCertification(request.certificationNumber)
        return Success(SuccessCode.SUCCESS_CHECK_MAIL)
    }

}
  • /user-certification은 사용자의 메일을 받습니다.
  • /user-certification/check는 메일의 인증번호를 받습니다.

Service

@Service
class UserMailService(
    private val javaMailSender: JavaMailSender,
    private val redisUtils: RedisUtils,
) {

    fun sendMail(email: String) {
        val certificationNumber: String = MailServiceUtils.certificationNum
        val message = getMailMessage(email, certificationNumber)
        redisUtils.setDataExpire(certificationNumber, email)
        javaMailSender.send(message)
    }

    fun checkCertification(certificationNumber: String) {
        redisUtils.getData(certificationNumber)
            ?: throw MailSendException("인증번호가 잘못되었거나 인증 시간이 초과되었습니다. 다시 확인해주세요.")
        redisUtils.deleteData(certificationNumber)
    }

    private fun getMailMessage(email: String, certificationNumber: String): MimeMessage {
        val message = javaMailSender.createMimeMessage()
        message.addRecipient(Message.RecipientType.TO, InternetAddress(email))
        message.subject = "[hannah-education] 본인 인증 메일"
        message.setText(getText(certificationNumber), "UTF-8", "html")
        return message
    }

    private fun getText(certificationNum: String): String {
        return MailServiceUtils.START_CONTENT +
                certificationNum +
                MailServiceUtils.END_CONTENT
    }

}
  • sendMail(email: String) : 사용자에게 메일을 보냅니다.
    1. MailServiceUtils에서 랜덤한 인증 번호를 가져옵니다.
    2. getMailMessage에서 사용자에게 보낼 메일 내용을 세팅하고 가져옵니다.
    3. redisUtils에서 데이터를 저장합니다.
    4. 최종적으로 javaMailSender에서 메일을 사용자에게 보냅니다.
  • checkCertification(certificationNumber: String) : 사용자의 인증 번호를 체크합니다.
    1. redisUtils에서 유효한 데이터를 조회합니다.
    2. 값이 존재하지 않으면 exception을 보내줍니다.
    3. 값이 존재하면 redis에 남아있는 값을 지워줍니다.

Utils

@Component
class RedisUtils(
    private val redisTemplate: RedisTemplate<String, String>,
) {

    private val DURATION_TIME = 1000 * 60 * 5L // 5분


    fun getData(key: String): String? {
        val valueOperations = redisTemplate.opsForValue()
        return valueOperations[key]
    }

    fun setDataExpire(key: String, value: String) {
        val valueOperations = redisTemplate.opsForValue()
        valueOperations.set(key, value, Duration.ofMillis(DURATION_TIME))
    }

    fun deleteData(key: String) {
        redisTemplate.delete(key)
    }

}
  • getData(key: String) : 레디스에 저장되어 있는 값을 조회합니다.
  • setDataExpire(key: String, value: String) : 레디스에 값을 저장합니다.
    1. 지금과 같은 경우는 key를 메일 주소, value를 인증 번호로 설정했습니다.
    2. 인증 시간은 5분으로 설정했습니다.
  • deleteData(key: String) : 레디스에 저장되어 있는 값을 삭제합니다.

MailServiceUtils은 메세지 포멧을 위한 html 내용을 포함하고 있습니다.
html 내용이 길다보니 코드를 첨부하지 않았습니다.

properties

메일 & 레디스 관련 설정입니다.

spring.mail.default-encoding=UTF-8
spring.mail.protocol=smtp
spring.mail.host=smtp.gmail.com
spring.mail.username=coals0329@dongyang.ac.kr // 1
spring.mail.password=secret // 2
spring.mail.port=587
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.required=true

spring.redis.host=localhost
spring.redis.port=6379
  1. 앱 비밀번호를 발급받은 이메일입니다.
  2. 앱 비밀번호입니다.
  3. spring-boot-starter-mail를 사용하면 JavaMailSender Bean을 생성할 필요 없이, 자동으로 생성됩니다. 그렇기 때문에 properties에 smtp 설정만 추가하면 됩니다.

계정 절차 (구글)

  1. 메일을 보낼 계정으로 접속합니다.

  2. Google 홀페이지 > Google 계정 관리로 접속합니다.

  3. 보안 > 앱 비밀번호로 이동합니다.

  4. 메일, 기기를 선택하고 생성을 누릅니다.

  5. 비밀번호를 저장합니다.

  6. 구글 메일로 접속합니다.

  7. 톱니바퀴 > 모든 설정 보기로 이동합니다.

  1. 설정을 완료합니다.
  • 모든 메일에 POP사용하기
  • IMAP 사용

부록

얕은 레디스 명령어

  • redis-cil -p 6379 : local에 있는 6379 포트의 redis 접속
  • redis-cil -p 6379 info : 해당 redis 서버 정보 확인
  • redis-cil -p 6379 monitor : 해당 redis 서버 모니터링
  • keys * : 모든 key 검색
  • ttl [key] : 키의 잔류 시간 확인

-끗- 긴 글 읽어주셔서 감사합니다 🙋🏻‍♀️

👉🏻 참고 사이트

profile
backend developer

0개의 댓글