From 509a41fd0a73d62b6fe393afabd9f7e115261fa6 Mon Sep 17 00:00:00 2001 From: kgc91747 Date: Wed, 7 Aug 2024 10:39:16 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20email=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=B0=BE=EA=B8=B0=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-2922-4057-81cd-756e62ddd13c_testimg1.jpg} | Bin ...-11a6-4026-82fb-5a1d0beb9130_testImg2.jpg} | Bin ...3-017a-4d3c-9c5c-aa0a2ada53f9_testimg1.jpg | Bin 8567 -> 0 bytes ...1a-4f48-885c-30bf45d63778_lectureImage.jpg | Bin 8567 -> 0 bytes ...08-41ad-96b9-9d25d5353c73_lectureImage.jpg | Bin 8567 -> 0 bytes backend/build.gradle | 2 +- .../global/config/PropertiesConfig.java | 4 +- .../edufocus/global/config/RedisConfig.java | 22 ++++++ .../global/properties/MailProperties.java | 15 ++++ .../mail/controller/MailController.java | 39 ++++++++++ .../edufocus/mail/service/MailService.java | 13 ++++ .../mail/service/MailServiceImpl.java | 69 ++++++++++++++++++ .../edufocus/redis/util/RedisUtil.java | 36 +++++++++ .../user/config/WebConfiguration.java | 2 +- .../user/controller/UserController.java | 26 ++++--- .../user/model/repository/UserRepository.java | 2 + .../user/model/service/UserService.java | 24 +++--- .../user/model/service/UserServiceImpl.java | 52 ++++++++----- .../src/main/resources/application.properties | 11 ++- 19 files changed, 277 insertions(+), 40 deletions(-) rename backend/backend/src/main/resources/images/{30d65b76-54cb-42ad-a53e-04691c6401ba_testimg3.jpg => 0a51d4af-2922-4057-81cd-756e62ddd13c_testimg1.jpg} (100%) rename backend/backend/src/main/resources/images/{427dc7fc-d22e-43a3-8fde-69bace73ee6a_lectureImage.jpg => 0bef3f29-11a6-4026-82fb-5a1d0beb9130_testImg2.jpg} (100%) delete mode 100644 backend/backend/src/main/resources/images/45b6ea03-017a-4d3c-9c5c-aa0a2ada53f9_testimg1.jpg delete mode 100644 backend/backend/src/main/resources/images/7fd1090b-af1a-4f48-885c-30bf45d63778_lectureImage.jpg delete mode 100644 backend/backend/src/main/resources/images/a69e91c4-5108-41ad-96b9-9d25d5353c73_lectureImage.jpg create mode 100644 backend/src/main/java/com/edufocus/edufocus/global/config/RedisConfig.java create mode 100644 backend/src/main/java/com/edufocus/edufocus/global/properties/MailProperties.java create mode 100644 backend/src/main/java/com/edufocus/edufocus/mail/controller/MailController.java create mode 100644 backend/src/main/java/com/edufocus/edufocus/mail/service/MailService.java create mode 100644 backend/src/main/java/com/edufocus/edufocus/mail/service/MailServiceImpl.java create mode 100644 backend/src/main/java/com/edufocus/edufocus/redis/util/RedisUtil.java diff --git a/backend/backend/src/main/resources/images/30d65b76-54cb-42ad-a53e-04691c6401ba_testimg3.jpg b/backend/backend/src/main/resources/images/0a51d4af-2922-4057-81cd-756e62ddd13c_testimg1.jpg similarity index 100% rename from backend/backend/src/main/resources/images/30d65b76-54cb-42ad-a53e-04691c6401ba_testimg3.jpg rename to backend/backend/src/main/resources/images/0a51d4af-2922-4057-81cd-756e62ddd13c_testimg1.jpg diff --git a/backend/backend/src/main/resources/images/427dc7fc-d22e-43a3-8fde-69bace73ee6a_lectureImage.jpg b/backend/backend/src/main/resources/images/0bef3f29-11a6-4026-82fb-5a1d0beb9130_testImg2.jpg similarity index 100% rename from backend/backend/src/main/resources/images/427dc7fc-d22e-43a3-8fde-69bace73ee6a_lectureImage.jpg rename to backend/backend/src/main/resources/images/0bef3f29-11a6-4026-82fb-5a1d0beb9130_testImg2.jpg diff --git a/backend/backend/src/main/resources/images/45b6ea03-017a-4d3c-9c5c-aa0a2ada53f9_testimg1.jpg b/backend/backend/src/main/resources/images/45b6ea03-017a-4d3c-9c5c-aa0a2ada53f9_testimg1.jpg deleted file mode 100644 index c53ac5e358df846b8d20f1928bd0860aa4302f24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8567 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 sendMail(@RequestParam String email) { + if (!userService.isEmailExist(email)) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + mailService.sendMail(email); + return new ResponseEntity<>(HttpStatus.OK); + } + + @GetMapping("/verify") + public ResponseEntity verifyCode(@RequestParam String code, @RequestParam String email) { + if (!mailService.verifyCode(code, email)) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(HttpStatus.OK); + } + +} diff --git a/backend/src/main/java/com/edufocus/edufocus/mail/service/MailService.java b/backend/src/main/java/com/edufocus/edufocus/mail/service/MailService.java new file mode 100644 index 0000000..1799126 --- /dev/null +++ b/backend/src/main/java/com/edufocus/edufocus/mail/service/MailService.java @@ -0,0 +1,13 @@ +package com.edufocus.edufocus.mail.service; + +import org.springframework.stereotype.Service; + +@Service +public interface MailService { + + void sendMail(String to); + + String createRandomCode(); + + boolean verifyCode(String code, String email); +} diff --git a/backend/src/main/java/com/edufocus/edufocus/mail/service/MailServiceImpl.java b/backend/src/main/java/com/edufocus/edufocus/mail/service/MailServiceImpl.java new file mode 100644 index 0000000..20859de --- /dev/null +++ b/backend/src/main/java/com/edufocus/edufocus/mail/service/MailServiceImpl.java @@ -0,0 +1,69 @@ +package com.edufocus.edufocus.mail.service; + +import com.edufocus.edufocus.redis.util.RedisUtil; +import com.edufocus.edufocus.user.model.entity.vo.User; +import com.edufocus.edufocus.user.model.repository.UserRepository; +import com.edufocus.edufocus.user.model.service.UserService; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Service; + +import java.util.NoSuchElementException; +import java.util.Random; + +@Service +@Slf4j +@ToString +@RequiredArgsConstructor +public class MailServiceImpl implements MailService { + + private final JavaMailSender mailSender; + + private final UserRepository userRepository; + + private final UserService userService; + + private final RedisUtil redisUtil; + + @Override + public void sendMail(String email) { + String code = createRandomCode(); + redisUtil.setDataExpire(code, email, 60 * 5L); + + SimpleMailMessage mail = createEmail(email, "[EDUFOCUS] 비밀번호 찾기 안내", code); + mailSender.send(mail); + } + + @Override + public boolean verifyCode(String code, String email) { + String registedEmail = redisUtil.getData(code); + + return registedEmail != null && registedEmail.equals(email); + } + + private SimpleMailMessage createEmail(String to, String title, String code) { + SimpleMailMessage message = new SimpleMailMessage(); + message.setTo(to); + message.setSubject(title); + message.setText("인증번호 6자리입니다 : " + code); + + return message; + } + + @Override + public String createRandomCode() { + StringBuilder sb = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 3; i++) { + sb.append((char) (random.nextInt(26) + 65)); + } + for (int i = 0; i < 3; i++) { + sb.append(random.nextInt(10)); + } + return sb.toString(); + } + +} diff --git a/backend/src/main/java/com/edufocus/edufocus/redis/util/RedisUtil.java b/backend/src/main/java/com/edufocus/edufocus/redis/util/RedisUtil.java new file mode 100644 index 0000000..ad9bf09 --- /dev/null +++ b/backend/src/main/java/com/edufocus/edufocus/redis/util/RedisUtil.java @@ -0,0 +1,36 @@ +package com.edufocus.edufocus.redis.util; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +@Component +@RequiredArgsConstructor +public class RedisUtil { + + private final StringRedisTemplate stringRedisTemplate; + + public String getData(String key) { + ValueOperations valueOperations = stringRedisTemplate.opsForValue(); + return valueOperations.get(key); + } + + public void setData(String key, String value) { + ValueOperations valueOperations = stringRedisTemplate.opsForValue(); + valueOperations.set(key, value); + } + + public void setDataExpire(String key, String value, long duration) { + ValueOperations valueOperations = stringRedisTemplate.opsForValue(); + Duration expireDuration = Duration.ofSeconds(duration); + valueOperations.set(key, value, expireDuration); + } + + public void deleteData(String key) { + stringRedisTemplate.delete(key); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/edufocus/edufocus/user/config/WebConfiguration.java b/backend/src/main/java/com/edufocus/edufocus/user/config/WebConfiguration.java index 0972d21..5899062 100644 --- a/backend/src/main/java/com/edufocus/edufocus/user/config/WebConfiguration.java +++ b/backend/src/main/java/com/edufocus/edufocus/user/config/WebConfiguration.java @@ -47,6 +47,6 @@ public class WebConfiguration implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns("/**") // 모든 경로에 대해 인터셉터 적용 - .excludePathPatterns("/v3/api-docs/**", "/swagger-resources/**", "/webjars/**", "/swagger-ui/**", "/auth/**", "/board/**", "/user/**", "/lecture/**", "/qna/**", "/quiz/**", "/video/**", "/registration/**", "/report/**"); // 인증 없이 접근 가능한 경로 설정 + .excludePathPatterns("/v3/api-docs/**", "/swagger-resources/**", "/webjars/**", "/swagger-ui/**", "/auth/**", "/board/**", "/user/**", "/lecture/**", "/qna/**", "/quiz/**", "/video/**", "/registration/**", "/report/**", "/mail/**"); // 인증 없이 접근 가능한 경로 설정 } } \ No newline at end of file diff --git a/backend/src/main/java/com/edufocus/edufocus/user/controller/UserController.java b/backend/src/main/java/com/edufocus/edufocus/user/controller/UserController.java index c077839..2aecbb3 100644 --- a/backend/src/main/java/com/edufocus/edufocus/user/controller/UserController.java +++ b/backend/src/main/java/com/edufocus/edufocus/user/controller/UserController.java @@ -32,9 +32,9 @@ public class UserController { private final JWTUtil jwtUtil; @PostMapping("/join") - public ResponseEntity join(@RequestBody RequestJoinDto requestJoinDto){ + public ResponseEntity join(@RequestBody RequestJoinDto requestJoinDto) { - if(userService.isUserIdExist(requestJoinDto.getUserId())) + if (userService.isUserIdExist(requestJoinDto.getUserId())) return new ResponseEntity<>("아이디가 중복 됐습니다.", HttpStatus.CONFLICT); userService.join(requestJoinDto); @@ -66,6 +66,14 @@ public class UserController { } } + // 비밀번호 찾기를 통한 변경 + @PutMapping("/updateforgottenpassword") + public ResponseEntity updatePassword(@RequestParam long userId, + @RequestParam String newPassword) { + userService.changeForgottenPassword(userId, newPassword); + return new ResponseEntity<>(HttpStatus.OK); + } + @Operation(summary = "로그인", description = "아이디와 비밀번호를 이용하여 로그인 처리.") @PostMapping("/login") public ResponseEntity> login( @@ -83,8 +91,8 @@ public class UserController { userService.saveRefreshToken(loginUser.getId(), refreshToken); - resultMap.put("name",loginUser.getName()); - resultMap.put("role",loginUser.getRole()); + resultMap.put("name", loginUser.getName()); + resultMap.put("role", loginUser.getRole()); resultMap.put("access-token", accessToken); setCookies(response, refreshToken); @@ -108,7 +116,7 @@ public class UserController { @Operation(summary = "Access Token 재발급", description = "만료된 access token 을 재발급 받는다.") @PostMapping("/refresh") - public ResponseEntity refreshToken(HttpServletRequest request,HttpServletResponse response) { + public ResponseEntity refreshToken(HttpServletRequest request, HttpServletResponse response) { Cookie[] cookies = request.getCookies(); String token = null; if (cookies != null) { @@ -120,9 +128,9 @@ public class UserController { } } - try{ + try { jwtUtil.checkToken(token); - }catch (Exception e){ + } catch (Exception e) { throw new InvalidTokenException(); } @@ -140,7 +148,7 @@ public class UserController { Map resultMap = new HashMap<>(); resultMap.put("access-token", accessToken); - userService.saveRefreshToken(userId,refreshToken); + userService.saveRefreshToken(userId, refreshToken); setCookies(response, refreshToken); @@ -175,7 +183,7 @@ public class UserController { } - private void setCookies(HttpServletResponse response, String refreshToken){ + private void setCookies(HttpServletResponse response, String refreshToken) { Cookie refreshCookie = new Cookie("refresh-token", refreshToken); refreshCookie.setPath("/"); refreshCookie.setHttpOnly(true); diff --git a/backend/src/main/java/com/edufocus/edufocus/user/model/repository/UserRepository.java b/backend/src/main/java/com/edufocus/edufocus/user/model/repository/UserRepository.java index 10e9f87..6aea378 100644 --- a/backend/src/main/java/com/edufocus/edufocus/user/model/repository/UserRepository.java +++ b/backend/src/main/java/com/edufocus/edufocus/user/model/repository/UserRepository.java @@ -31,4 +31,6 @@ public interface UserRepository extends JpaRepository { Optional findByUserId(String userId); + Optional findByEmail(String email); + } diff --git a/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserService.java b/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserService.java index 7b2d101..0737045 100644 --- a/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserService.java +++ b/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserService.java @@ -6,23 +6,27 @@ import com.edufocus.edufocus.user.model.entity.dto.RequestJoinDto; import com.edufocus.edufocus.user.model.entity.vo.User; public interface UserService { - void join(RequestJoinDto requestJoinDto); + void join(RequestJoinDto requestJoinDto); - User login(User user); + User login(User user); - void saveRefreshToken(Long id, String refreshToken); + void saveRefreshToken(Long id, String refreshToken); - String getRefreshToken(Long id); + String getRefreshToken(Long id); - void deleteRefreshToken(Long id); + void deleteRefreshToken(Long id); - User userInfo(Long id); + User userInfo(Long id); - String getUserName(Long id); + String getUserName(Long id); - void changeUserInfo(InfoDto infoDto,Long id); + void changeUserInfo(InfoDto infoDto, Long id); - void changePassword(PasswordDto passwordDto,Long id); + void changePassword(PasswordDto passwordDto, Long id); - boolean isUserIdExist(String userId); + boolean isUserIdExist(String userId); + + boolean isEmailExist(String email); + + void changeForgottenPassword(Long id, String newPassword); } diff --git a/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserServiceImpl.java b/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserServiceImpl.java index 77fd4ca..9cd9705 100644 --- a/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserServiceImpl.java +++ b/backend/src/main/java/com/edufocus/edufocus/user/model/service/UserServiceImpl.java @@ -3,11 +3,11 @@ package com.edufocus.edufocus.user.model.service; import com.edufocus.edufocus.user.model.entity.dto.InfoDto; import com.edufocus.edufocus.user.model.entity.dto.PasswordDto; -import com.edufocus.edufocus.user.util.PasswordUtils; import com.edufocus.edufocus.user.model.entity.dto.RequestJoinDto; import com.edufocus.edufocus.user.model.entity.vo.User; import com.edufocus.edufocus.user.model.exception.UserException; import com.edufocus.edufocus.user.model.repository.UserRepository; +import com.edufocus.edufocus.user.util.PasswordUtils; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -23,8 +23,7 @@ public class UserServiceImpl implements UserService { private final UserRepository userRepository; - public void join(RequestJoinDto requestJoinDto) - { + public void join(RequestJoinDto requestJoinDto) { User user = User.builder() .userId(requestJoinDto.getUserId()) .email(requestJoinDto.getEmail()) @@ -36,7 +35,7 @@ public class UserServiceImpl implements UserService { } - public User login(User user){ + public User login(User user) { Optional findUser = userRepository.findByUserId(user.getUserId()); if (findUser.isEmpty()) { @@ -63,32 +62,29 @@ public class UserServiceImpl implements UserService { } - - - @Override - public String getUserName(Long id){ + public String getUserName(Long id) { return userRepository.findById(id).get().getName(); } @Override - public void changeUserInfo(InfoDto infoDto, Long id){ + public void changeUserInfo(InfoDto infoDto, Long id) { User user = userRepository.findById(id).orElseThrow(IllegalArgumentException::new); if (infoDto.getName() != null) user.setName(infoDto.getName()); - if(infoDto.getEmail()!=null) + if (infoDto.getEmail() != null) user.setEmail(infoDto.getEmail()); userRepository.save(user); -} + } @Override - public void changePassword(PasswordDto passwordDto, Long id){ + public void changePassword(PasswordDto passwordDto, Long id) { User user = userRepository.findById(id).orElse(null); if (user == null) { @@ -114,30 +110,52 @@ public class UserServiceImpl implements UserService { } public String getTempPassword() { - char[] charSet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + char[] charSet = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; String str = ""; int idx = 0; - for (int i=0; i<10; i++) { + for (int i = 0; i < 10; i++) { idx = (int) (charSet.length * Math.random()); str += charSet[idx]; } return str; } + @Override - public void saveRefreshToken(Long id, String refreshToken){ + public void saveRefreshToken(Long id, String refreshToken) { userRepository.saveRefreshToken(id, refreshToken); } @Override - public String getRefreshToken(Long id){ + public String getRefreshToken(Long id) { return userRepository.getRefreshToken(id); } @Override - public void deleteRefreshToken(Long id){ + public void deleteRefreshToken(Long id) { userRepository.deleteRefreshToken(id); } + @Override + public boolean isEmailExist(String email) { + Optional user = userRepository.findByEmail(email); + + return user.isPresent(); + } + + @Override + public void changeForgottenPassword(Long id, String newPassword) { + User user = userRepository.findById(id).orElse(null); + + if (user == null) { + throw new UserException("User not found"); + } + + // Hash the new password before saving + user.setPassword(PasswordUtils.hashPassword(newPassword)); + userRepository.save(user); + } + + } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index aa22dc0..479d1de 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -29,4 +29,13 @@ spring.rabbitmq.host=${RABBITMQ_HOST} spring.rabbitmq.port=${RABBITMQ_PORT} spring.rabbitmq.username=${RABBITMQ_USERNAME} spring.rabbitmq.password=${RABBITMQ_PASSWORD} -image.path=${IMAGE_PATH} \ No newline at end of file +image.path=${IMAGE_PATH} +spring.mail.host=smtp.gmail.com +spring.mail.port=${MAIL_PORT} +spring.mail.username=${MAIL_NAME} +spring.mail.password=${MAIL_PASSWORD} +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.timeout=5000 +spring.mail.properties.mail.smtp.starttls.enable=true +spring.data.redis.host=${REDIS_HOST} +spring.data.redis.port=${REDIS_PORT} \ No newline at end of file