Skip to content

Commit

Permalink
Merge pull request #100 from TEAM-MODDY/feat/#98
Browse files Browse the repository at this point in the history
#98 #89 [feat] sms 전송 기능 구현 및 휴대폰 인증 api 기능 구현
  • Loading branch information
KWY0218 authored Jan 12, 2024
2 parents a0ac4f1 + 139b967 commit d1fc6f9
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 8 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ repositories {
}

dependencies {
// coolsms
implementation group: 'io.awspring.cloud', name: 'spring-cloud-aws-messaging', version: '2.3.1'

//JWT
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
@Getter
@ToString
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class SuccessNonDataResponse<T> {
public class SuccessNonDataResponse {
private final int code;
private final String message;

public static SuccessNonDataResponse success(SuccessCode successCode) {
return new SuccessNonDataResponse<>(successCode.getHttpStatus().value(), successCode.getMessage());
return new SuccessNonDataResponse(successCode.getHttpStatus().value(), successCode.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ public enum SuccessCode {
OPEN_CHAT_GET_SUCCESS(HttpStatus.OK, "오픈채팅방 연결 성공"),
USER_MY_PAGE_SUCCESS(HttpStatus.OK, "마이페이지 유저 정보 조회 성공입니다."),
OFFER_ACCEPT_SUCCESS(HttpStatus.OK, "제안서 승락 성공입니다."),
FIND_REGION_LIST_SUCCESS(HttpStatus.OK, "희망 지역 리스트 조회 성공입니다."),
POST_OFFER_SUCCESS(HttpStatus.OK, "제안서 작성 성공입니다.");
POST_OFFER_SUCCESS(HttpStatus.OK, "제안서 작성 성공입니다."),
SEND_VERIFICATION_CODE_SUCCESS(HttpStatus.OK, "전화번호 인증 요청 성공입니다."),
FIND_REGION_LIST_SUCCESS(HttpStatus.OK, "희망 지역 리스트 조회 성공입니다.");

private final HttpStatus httpStatus;
private final String message;
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/moddy/server/common/util/SmsUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.moddy.server.common.util;

import com.moddy.server.external.sms.SmsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class SmsUtil {
private final SmsService smsService;

public boolean sendVerificationCode(String to, String verificationCode) {
return smsService.sendSms(to, verificationCode);
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/moddy/server/config/sms/AwsSnsConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.moddy.server.config.sms;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AwsSnsConfig {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;

@Bean
public AmazonSNSClient amazonSNSClient() {
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonSNSClient) AmazonSNSClientBuilder
.standard()
.withRegion("ap-northeast-1")
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
}
}
22 changes: 20 additions & 2 deletions src/main/java/com/moddy/server/controller/auth/AuthController.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.moddy.server.controller.auth;

import com.moddy.server.common.dto.ErrorResponse;
import com.moddy.server.common.dto.SuccessNonDataResponse;
import com.moddy.server.common.dto.SuccessResponse;
import com.moddy.server.common.exception.enums.SuccessCode;
import com.moddy.server.common.util.SmsUtil;
import com.moddy.server.config.resolver.kakao.KakaoCode;
import com.moddy.server.controller.model.dto.request.ModelCreateRequest;
import com.moddy.server.controller.auth.dto.request.PhoneNumberRequestDto;
import com.moddy.server.controller.auth.dto.response.LoginResponseDto;
import com.moddy.server.controller.designer.dto.response.UserCreateResponse;
import com.moddy.server.controller.auth.dto.response.RegionResponse;
import com.moddy.server.controller.designer.dto.request.DesignerCreateRequest;
import com.moddy.server.controller.designer.dto.response.UserCreateResponse;
import com.moddy.server.controller.model.dto.request.ModelCreateRequest;
import com.moddy.server.service.auth.AuthService;
import com.moddy.server.service.designer.DesignerService;
import com.moddy.server.service.model.ModelService;
Expand All @@ -32,6 +35,7 @@

import java.util.List;

import static com.moddy.server.common.exception.enums.SuccessCode.SEND_VERIFICATION_CODE_SUCCESS;
import static com.moddy.server.common.exception.enums.SuccessCode.SOCIAL_LOGIN_SUCCESS;

@Tag(name = "Auth Controller", description = "로그인 및 회원 가입 관련 API 입니다.")
Expand All @@ -43,6 +47,7 @@ public class AuthController {
private final AuthService authService;
private final DesignerService designerService;
private final ModelService modelService;
private final SmsUtil smsUtil;

@Operation(summary = "[KAKAO CODE] 로그인 API")
@ApiResponses(value = {
Expand Down Expand Up @@ -102,4 +107,17 @@ public SuccessResponse<UserCreateResponse> createModel(
return SuccessResponse.success(SuccessCode.MODEL_CREATE_SUCCESS, modelService.createModel(request.getHeader(ORIGIN), kakaoCode, modelCreateRequest));
}

@Operation(summary = "[SMS 기능 미완성] 인증번호 요청 API", description = "인증번호 요청 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "전화번호 인증 요청 성공입니다."),
@ApiResponse(responseCode = "400", description = "유효하지 않은 카카오 코드를 입력했습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "유효하지 않은 값을 입력했습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "500", description = "서버 내부 오류", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@PostMapping("/phoneNumber")
public SuccessNonDataResponse sendVerificationCodeMessageToUser(@RequestBody PhoneNumberRequestDto phoneNumberRequestDto) {
authService.sendVerificationCodeMessageToUser(phoneNumberRequestDto.phoneNumber());
return SuccessNonDataResponse.success(SEND_VERIFICATION_CODE_SUCCESS);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.moddy.server.controller.auth.dto.request;

public record PhoneNumberRequestDto(String phoneNumber) {
}
25 changes: 25 additions & 0 deletions src/main/java/com/moddy/server/domain/verify/UserVerification.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.moddy.server.domain.verify;

import com.moddy.server.domain.BaseTimeEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;

@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserVerification extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
private String phoneNumber;
@NotNull
private String verificationCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.moddy.server.domain.verify.repository;

import com.moddy.server.domain.verify.UserVerification;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserVerificationRepository extends JpaRepository<UserVerification, Long> {
Optional<UserVerification> findByPhoneNumber(String phoneNumber);

void deleteByPhoneNumber(String phoneNumber);
}
7 changes: 7 additions & 0 deletions src/main/java/com/moddy/server/external/sms/SmsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.moddy.server.external.sms;

public interface SmsService {
String MESSAGE_FORM = "[%s] moddy에서 보낸 인증번호입니다. 해당 인증번호는 3분간 유효합니다.";

boolean sendSms(String to, String verificationCode);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.moddy.server.external.sms.impl;

import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.PublishRequest;
import com.moddy.server.external.sms.SmsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class AwsSmsServiceImpl implements SmsService {
private final AmazonSNSClient amazonSNSClient;
private static final String KR = "+82";

@Override
public boolean sendSms(String to, String verificationCode) {
PublishRequest request = new PublishRequest();
request.setMessage(String.format(MESSAGE_FORM, verificationCode));
request.setPhoneNumber(KR + to);

amazonSNSClient.publish(request);
return true;
}
}
28 changes: 26 additions & 2 deletions src/main/java/com/moddy/server/service/auth/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,37 @@

import com.moddy.server.common.dto.TokenPair;
import com.moddy.server.common.exception.model.NotFoundException;
import com.moddy.server.common.util.SmsUtil;
import com.moddy.server.common.util.VerificationCodeGenerator;
import com.moddy.server.config.jwt.JwtService;
import com.moddy.server.controller.auth.dto.response.LoginResponseDto;
import com.moddy.server.controller.auth.dto.response.RegionResponse;
import com.moddy.server.controller.designer.dto.response.UserCreateResponse;
import com.moddy.server.domain.region.repository.RegionJpaRepository;
import com.moddy.server.domain.user.User;
import com.moddy.server.domain.user.repository.UserRepository;
import com.moddy.server.domain.verify.UserVerification;
import com.moddy.server.domain.verify.repository.UserVerificationRepository;
import com.moddy.server.external.kakao.service.KakaoSocialService;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.moddy.server.common.exception.enums.ErrorCode.USER_NOT_FOUND_EXCEPTION;

@Service
@RequiredArgsConstructor
public class AuthService {
private final SmsUtil smsUtil;
private final JwtService jwtService;
private final KakaoSocialService kakaoSocialService;
private final UserRepository userRepository;
private final RegionJpaRepository regionJpaRepository;
private final UserVerificationRepository userVerificationRepository;

public LoginResponseDto login(final String baseUrl, final String kakaoCode) {
String kakaoId = kakaoSocialService.getIdFromKakao(baseUrl, kakaoCode);
Expand All @@ -34,7 +42,7 @@ public LoginResponseDto login(final String baseUrl, final String kakaoCode) {
return new LoginResponseDto(tokenPair.accessToken(), tokenPair.refreshToken(), user.getRole().name());
}

public List<RegionResponse> getRegionList(){
public List<RegionResponse> getRegionList() {

List<RegionResponse> regionResponseList = regionJpaRepository.findAll().stream().map(region -> {
RegionResponse regionResponse = new RegionResponse(
Expand All @@ -47,12 +55,28 @@ public List<RegionResponse> getRegionList(){
return regionResponseList;
}

public UserCreateResponse createUserToken(String useId){
public UserCreateResponse createUserToken(String useId) {

TokenPair tokenPair = jwtService.generateTokenPair(useId);
UserCreateResponse userCreateResponse = new UserCreateResponse(tokenPair.accessToken(), tokenPair.refreshToken());

return userCreateResponse;
}

@Transactional
public void sendVerificationCodeMessageToUser(String phoneNumber) {
Optional<UserVerification> userVerification = userVerificationRepository.findByPhoneNumber(phoneNumber);
if (userVerification.isPresent()) {
userVerificationRepository.deleteByPhoneNumber(phoneNumber);
}

String verificationCode = VerificationCodeGenerator.generate();
// smsUtil.sendVerificationCode(phoneNumber, verificationCode);

UserVerification newUserVerification = UserVerification.builder()
.phoneNumber(phoneNumber)
.verificationCode(verificationCode)
.build();
userVerificationRepository.save(newUserVerification);
}
}

0 comments on commit d1fc6f9

Please sign in to comment.