Skip to content

Commit

Permalink
feat: 문자 인증 코드 요청을 1분에 한 번 요청하도록 기능 구현 (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
pdohyung committed Nov 19, 2023
1 parent 0388e6b commit 710e95d
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/main/java/com/backend/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.requestMatchers(mvcMatcherBuilder.pattern("/api/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/mail/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/s3/create")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/sms")).permitAll()
.anyRequest().authenticated())
.exceptionHandling()
.authenticationEntryPoint(entryPoint);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.backend.domain.mail.controller;

import com.backend.domain.mail.dto.request.MailRequest;
import com.backend.domain.mail.dto.request.SmsRequest;
import com.backend.domain.mail.service.MailService;
import com.backend.error.ErrorCode;
import com.backend.error.exception.custom.BusinessException;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
Expand All @@ -21,4 +23,17 @@ public class MailController {
public ResponseEntity<Integer> sendCode(@Valid @RequestBody MailRequest emailRequest) {
return ResponseEntity.ok(mailService.sendAuthenticationCode(emailRequest));
}

@RateLimiter(name = "jedero", fallbackMethod = "rateLimiterFallback")
@GetMapping("/sms")
public ResponseEntity<Integer> sendSMS(@Valid @RequestBody SmsRequest smsRequest) {
int result = mailService.sendSMS(smsRequest);
return ResponseEntity.ok(result);
}

public ResponseEntity<String> rateLimiterFallback(Throwable t) {
// HttpHeaders responseHeaders = new HttpHeaders();
// responseHeaders.set("Retry-After", "10s");
throw new BusinessException(ErrorCode.TOO_MANY_SMS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.backend.domain.mail.dto.request;

import jakarta.validation.constraints.NotEmpty;

public record SmsRequest(@NotEmpty String toNumber) {
}
47 changes: 45 additions & 2 deletions src/main/java/com/backend/domain/mail/service/MailService.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
package com.backend.domain.mail.service;

import com.backend.domain.mail.dto.request.MailRequest;
import com.backend.domain.mail.dto.request.SmsRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.nurigo.sdk.NurigoApp;
import net.nurigo.sdk.message.model.Message;
import net.nurigo.sdk.message.request.SingleMessageSendingRequest;
import net.nurigo.sdk.message.response.SingleMessageSentResponse;
import net.nurigo.sdk.message.service.DefaultMessageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
@RequiredArgsConstructor
@Slf4j
public class MailService {

private final JavaMailSender javaMailSender;
@Value("{mail.mail.username}")

private DefaultMessageService messageService;

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

@Value("${coolsms.api.key}")
private String apiKey;

@Value("${coolsms.api.secret}")
private String apiSecret;

@Value("${coolsms.api.fromNumber}")
private String fromNumber;


public int sendAuthenticationCode(MailRequest mailRequest) {
int code = (int) (Math.random() * 900000) + 100000;

Expand All @@ -31,4 +55,23 @@ public int sendAuthenticationCode(MailRequest mailRequest) {

return code;
}
}

public int sendSMS(SmsRequest smsRequest) {
Message message = new Message();
this.messageService = NurigoApp.INSTANCE.initialize(apiKey, apiSecret, "https://api.coolsms.co.kr");

Random rand = new Random();
String code = IntStream.range(0, 4)
.mapToObj(i -> Integer.toString(rand.nextInt(10)))
.collect(Collectors.joining());

message.setFrom(fromNumber);
message.setTo(smsRequest.toNumber());
message.setText("[제대로] 인증번호를 입력해주세요.\n인증번호: " + code);

SingleMessageSentResponse response = messageService.sendOne(new SingleMessageSendingRequest(message));
log.info("SMS 메세지 결과 = {}", response);

return Integer.parseInt(code);
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/backend/error/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public enum ErrorCode {
INVALID_GROUP_TYPE(BAD_REQUEST, "잘못된 그룹 종류입니다."),
INVALID_PASSWORD(BAD_REQUEST, "잘못된 비밀번호입니다."),
IMAGE_UPLOAD_FAIL(BAD_REQUEST, "이미지 업로드에 실패했습니다."),
INVALID_FILE(BAD_REQUEST, "잘못된 파일 형식입니다.");
INVALID_FILE(BAD_REQUEST, "잘못된 파일 형식입니다."),
TOO_MANY_SMS(TOO_MANY_REQUESTS, "짧은 시간에 너무 많은 요청을 보냈습니다. 1분 후에 재시도하세요.");

private final int code;
private final String message;
Expand Down

0 comments on commit 710e95d

Please sign in to comment.