Skip to content

Commit

Permalink
feat/member-email-verify-1: 이메일 인증 로직 추가
Browse files Browse the repository at this point in the history
- 이메일 인증번호 생성 : POST, Body로 email 전송, redis로 3분 유효 캐시인 인증코드 생성 (약 5초 정도 걸림)
- 인증번호 검증 : GET, Param으로 email, verifyCode로 캐시값에서 키 값 가져와 유효성 검증
  • Loading branch information
KooSuYeon committed Jan 15, 2025
1 parent b25a061 commit d4107d7
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/main/java/com/dife/api/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Excepti
"/favicon.ico",
"/api/v1/api-docs/**",
"/api/members/register",
"/api/members/email",
"/api/members/check/**",
"/api/members/refresh-token",
"/api/members/change-password",
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/dife/api/controller/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ public class MemberController implements SwaggerMemberController {
private final MemberService memberService;
private final JWTUtil jwtUtil;

@PostMapping("/email")
public ResponseEntity<RegisterResponseDto> checkEmail(@Valid @RequestBody CheckEmailDto dto) {

memberService.checkEmail(dto);

return ResponseEntity.ok().build();
}

@GetMapping("/email")
public ResponseEntity<RegisterResponseDto> verifyEmail(
@RequestParam(name = "email", required = false) String email,
@RequestParam(name = "verifyCode", required = false) String verifyCode) {
memberService.verifyEmail(email, verifyCode);

return ResponseEntity.ok().build();
}

@PostMapping("/register")
public ResponseEntity<RegisterResponseDto> registerEmailAndPassword(
@Valid @RequestBody RegisterEmailAndPasswordRequestDto dto) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/dife/api/jwt/JWTFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ protected void doFilterInternal(

private boolean isExemptPath(String servletPath) {
return servletPath.startsWith("/api/members/register")
|| servletPath.equals("/api/members/email")
|| servletPath.equals("/api/members/change-password")
|| servletPath.equals("/api/members/login")
|| servletPath.equals("/health")
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/com/dife/api/model/dto/CheckEmailDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.dife.api.model.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@RequiredArgsConstructor
public class CheckEmailDto {

private String email;
}
14 changes: 14 additions & 0 deletions src/main/java/com/dife/api/model/dto/VerifyEmailDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.dife.api.model.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@RequiredArgsConstructor
public class VerifyEmailDto {

private String email;
private String verifyCode;
}
34 changes: 34 additions & 0 deletions src/main/java/com/dife/api/redis/RedisUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.dife.api.redis;

import java.time.Duration;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class RedisUtil {

private final StringRedisTemplate stringRedisTemplate;

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

public void setData(String key, String value) {
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set(key, value);
}

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

public void deleteData(String key) {
stringRedisTemplate.delete(key);
}
}
31 changes: 31 additions & 0 deletions src/main/java/com/dife/api/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.dife.api.jwt.JWTUtil;
import com.dife.api.model.*;
import com.dife.api.model.dto.*;
import com.dife.api.redis.RedisUtil;
import com.dife.api.repository.*;
import java.util.*;
import java.util.function.Function;
Expand Down Expand Up @@ -72,6 +73,36 @@ public class MemberService {
private static final long ACCESS_TOKEN_VALIDITY_DURATION = 60 * 60 * 1000L;
private static final long REFRESH_TOKEN_VALIDITY_DURATION = 90 * 24 * 60 * 60 * 1000L;

private final RedisUtil redisUtil;

public void checkEmail(CheckEmailDto dto) {
String email = dto.getEmail();

if (memberRepository.existsByEmail(email))
throw new DuplicateMemberException("이미 가입되어있는 이메일입니다");

Random random = new Random();
String verifyCode = String.format("%04d", random.nextInt(10000));
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setTo(email);
simpleMailMessage.setSubject("🤿 DIFE 이메일 인증 🤿");
simpleMailMessage.setText(
"이메일 인증을 위해 아래 인증번호를 부여해드립니다!\n" + "회원가입 페이지로 돌아가 주세요!" + "인증번호 : " + verifyCode + "\n");
javaMailSender.send(simpleMailMessage);
redisUtil.setDataExpire(email, verifyCode, 60 * 3L);
}

public void verifyEmail(String email, String verifyCode) {
String storedVerifyCode = redisUtil.getData(email);

if (storedVerifyCode == null) {
throw new MemberNullException("인증번호가 만료되었거나 존재하지 않습니다.");
}
if (!storedVerifyCode.equals(verifyCode)) {
throw new MemberNullException("인증번호가 일치하지 않습니다!");
}
}

public RegisterResponseDto registerEmailAndPassword(RegisterEmailAndPasswordRequestDto dto) {

registerValidator.registerValidate(dto.getEmail(), dto.getPassword());
Expand Down

0 comments on commit d4107d7

Please sign in to comment.