반응형

목차

1. 개발환경

2. 의존성 추가

3. Gmail SMTP 설정

4. Redis 설치

5. application.properties 작성

6. RedisConfig 작성

7. RedisUtil 작성

8. EmailAuthResponseDto 작성

9. EmailController 작성

10. EmailService 작성

11. 테스트

 

 

 

 

1. 개발환경

Java 17

Spring Boot 3.1.8

Gradle 8.5

 

 

 

 

 

2. 의존성 추가

    // SMTP
    implementation 'org.springframework.boot:spring-boot-starter-mail'

    // Redis
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'

SMTP와 Redis의 의존성을 build.gradle에 추가해 줍니다.

 

 

3. Gmail SMTP 설정

 

3-1

구글로그인 후 지메일로 들어갑니다.

 

 

3-2

오른쪽 상단의 톱니바퀴 버튼을 누른 뒤 <모든 설정 보기> 버튼을 클릭합니다.

 

 

3-3

 

전달 및 POP/IMAP를 눌러주신 후 사진과 같이 체크한 뒤 <변경사항 저장> 버튼을 눌러 저장해 줍니다.

 

 

3-4

이제 우측 상단의 프로필버튼을 눌러서 <Google 계정 관리>를 클릭해 줍니다.

 

 

 

3-5

이 화면이 뜰 텐데 여기서 보안을 클릭해 줍니다

 

 

 

3-6

스크롤을 내린 뒤 Google에 로그인하는 방법 탭에서 <2단계 인증>을 클릭해 줍니다.

 

 

 

3-7

스크롤을 제일 밑으로 내리면 앱 비밀번호 탭이 있습니다. 클릭해 줍니다.

 

 

 

3-8

사용할 이름을 적고 만들기를 눌러줍니다

 

 

 

3-9

다음과 같이 비밀번호가 뜰 텐데 추후 application.properties에 작성해야 하니 따로 저장해 둡니다.

 

 

 

 

4. Redis 설치

https://ngwdeveloper.tistory.com/94

 

[Redis] Redis 설치 방법

Redis NoSQL DB의 한 종류이며 우리가 흔히 사용하는 MYSQL, Orcal DB, PostgreSQL 등 RDBMS와 다르게 NoSQL DB이다. 그렇다면 무슨 차이이고 어느 상황에 사용해야 할까? RDBMS와 NoSQL의 차이 RDBMS (관계형 DB) - 데

ngwdeveloper.tistory.com

설치가 안되어있으신 분들은 위 링크에 들어가서 따라 해 주시면 됩니다. 만약 설치가 되어있다면 넘어가셔도 됩니다.

 

 

 

 

 

5. application.properties 작성

# Email Properties
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=지메일주소@gmail.com
spring.mail.password=2차비밀번호
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

SMTP의 properties 작성법입니다. 아까 발급받은 본인의 지메일 주소와 저장해 둔 비밀번호를 입력해 주시면 됩니다.

 

#Redis
spring.data.redis.host = localhost
spring.data.redis.port = 6379

만약 Redis설치를 방금 하시고 설정이 되지 않으신 상태라면 위 코드를 추가로 properties에 넣어줍니다.

 

 

 

 

 

6. RedisConfig 작성

@Getter
@Configuration
@RequiredArgsConstructor
@EnableRedisRepositories
public class RedisConfig {
    @Value("${spring.data.redis.host}")
    private String host;

    @Value("${spring.data.redis.port}")
    private int port;

    // 내장 / 외부 Redis 연결
    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        return new LettuceConnectionFactory(host, port);
    }

    /*
     * RedisConnection 에서 넘겨준 byte 값을 직렬화 RedisTemplate 은
     * Redis 데이터를 저장하고 조회하는 기능을 하는 클래스 REdis cli 를 사용해 Redis 데이터를 직접 조회할때,
     * Redis 데이터를 문자열로 반환하기 위한 설정
     */
    @Bean
    public RedisTemplate<String, String> redisTemplate(){
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

 

 

 

 

 

7. RedisUtil 작성

@Service
@RequiredArgsConstructor
public class RedisUtil {

    private final StringRedisTemplate redisTemplate;

    public String getData(String key) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        return valueOperations.get(key);
    }

    public boolean existData(String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }

    public void setDataExpire(String key, String value, long duration) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        Duration expireDuration = Duration.ofSeconds(duration);
        valueOperations.set(key, value, expireDuration);
    }

    public void deleteData(String key) {
        redisTemplate.delete(key);
    }

}

 

 

 

 

8. EmailAuthResponseDto 작성

@Getter
public class EmailAuthResponseDto {
    private boolean success;
    private String responseMessage;

    public EmailAuthResponseDto(boolean success, String responseMessage){
        this.success = success;
        this.responseMessage = responseMessage;
    }
}

응답결과를 담을 DTO입니다. 성공, 실패 여부와 메시지를 담아서 반환합니다.

 

 

 

 

 

9. EmailController 작성

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/email")
public class EmailController {

    private final EmailService emailService;

    // 인증번호 전송
    @GetMapping("/auth")
    public EmailAuthResponseDto sendAuthCode(@RequestParam String address) {
        return emailService.sendEmail(address);
    }

    // 인증번호 검증
    @PostMapping("/auth")
    public EmailAuthResponseDto checkAuthCode(@RequestParam String address, @RequestParam String authCode) {
        return emailService.validateAuthCode(address, authCode);
    }
}

사용할 컨트롤러입니다. 인증번호를 전송하고 검증하는 두 개의 컨트롤러만 사용합니다. 필요한 게 있다면 추가로 작성하셔서 사용하시면 됩니다.

 

 

 

 

 

10. EmailService 작성

@Service
@RequiredArgsConstructor
public class EmailService {

    @Value("${spring.mail.username}")
    private String senderEmail;

    private final JavaMailSender mailSender;
    private final RedisUtil redisUtil;

    public EmailAuthResponseDto sendEmail(String toEmail) {
        if (redisUtil.existData(toEmail)) {
            redisUtil.deleteData(toEmail);
        }

        try {
            MimeMessage emailForm = createEmailForm(toEmail);
            mailSender.send(emailForm);
            return new EmailAuthResponseDto(true, "인증번호가 메일로 전송되었습니다.");
        } catch (MessagingException | MailSendException e) {
            return new EmailAuthResponseDto(false, "메일 전송 중 오류가 발생하였습니다. 다시 시도해주세요.");
        }
    }

    private MimeMessage createEmailForm(String email) throws MessagingException {

        String authCode = String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));

        MimeMessage message = mailSender.createMimeMessage();
        message.setFrom(senderEmail);
        message.setRecipients(MimeMessage.RecipientType.TO, email);
        message.setSubject("인증코드입니다.");
        message.setText(setContext(authCode), "utf-8", "html");

        redisUtil.setDataExpire(email, authCode, 10 * 60L); // 10분

        return message;
    }

    private String setContext(String authCode) {
        String body = "";
        body += "<h4>" + "인증 코드를 입력하세요." + "</h4>";
        body += "<h2>" + "[" + authCode + "]" + "</h2>";
        return body;
    }

    public EmailAuthResponseDto validateAuthCode(String email, String authCode) {
        String findAuthCode = redisUtil.getData(email);
        if (findAuthCode == null) {
            return new EmailAuthResponseDto(false, "인증번호가 만료되었습니다. 다시 시도해주세요.");
        }

        if (findAuthCode.equals(authCode)) {
            return new EmailAuthResponseDto(true, "인증 성공에 성공했습니다.");

        } else {
            return new EmailAuthResponseDto(false, "인증번호가 일치하지 않습니다.");
        }
    }
}

서비스 코드입니다. message에 담을 내용을 set해준 뒤 반환하는 메서드, 인증코드를 입력하도록 바디에 넣어서 반환하는 메서드, 인증번호를 검증하는 메서드로 이루어져 있습니다.

 

 

 

 

 

11. 테스트

인증번호를 수신할 이메일을 address 값으로 지정해 준 뒤 GET 해주면 정상적으로 보내졌다는 true와 메시지, 200 코드가 반환됩니다.

 

 

메시지함에 들어가도 정상적으로 수신된 걸 확인할 수 있습니다.

 

 

RequestParam방식으로 address에는 인증할 이메일, authCode에 인증번호를 넣고 POST 해본 결과 정상적으로 인증에 성공된 것을 확인할 수 있습니다.

반응형

+ Recent posts