Skip to content

Commit

Permalink
Merge pull request #21 from NARAE-FLIWITH/feat/tempoaryPw
Browse files Browse the repository at this point in the history
feat: 임시 비밀번호 메일 발송, 비밀번호 변경
  • Loading branch information
jjunjji authored Jul 12, 2024
2 parents 1fc5ec3 + 06240c3 commit 69d8429
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.requestMatchers("/user/nickname").permitAll()
.requestMatchers("/user/reissue").permitAll()
.requestMatchers("/user/authemail").permitAll()
.requestMatchers("/user/temporary-password").permitAll()
.requestMatchers("/user").permitAll()
.requestMatchers("/admin/**").permitAll()
.anyRequest().authenticated()
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/narae/fliwith/controller/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,16 @@ public ResponseEntity<BaseRes<Void>> checkAuthEmail(@RequestParam String email)
return ResponseEntity.ok(BaseRes.create(HttpStatus.OK.value(), "이메일 인증에 성공했습니다."));
}

@GetMapping("/temporary-password")
public ResponseEntity<BaseRes<Void>> temporaryPassword(@RequestParam String email) {
userService.temporaryPassword(email);
return ResponseEntity.ok(BaseRes.create(HttpStatus.OK.value(), "임시 비밀번호 발송에 성공했습니다."));
}

@PostMapping("/change-password")
public ResponseEntity<BaseRes<Void>> changePassword(@AuthenticationPrincipal CustomUser customUser, @RequestBody NewPasswordReq newPasswordReq) {
userService.changePassword(customUser.getEmail(), newPasswordReq);
return ResponseEntity.ok(BaseRes.create(HttpStatus.OK.value(), "비밀번호 변경에 성공했습니다."));
}

}
3 changes: 3 additions & 0 deletions src/main/java/com/narae/fliwith/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ public void completeSignup(){
signupStatus = SignupStatus.COMPLETE;
}

public void changePWd(String encodedPw) {
pw = encodedPw;
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/narae/fliwith/dto/UserReq.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,14 @@ public static class EmailReq{
public static class NicknameReq{
private String nickname;
}

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class NewPasswordReq{
private String email;
private String currentPassword;
private String newPassword;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public enum UserExceptionList {
ALREADY_LOGOUT_ERROR("U0005", HttpStatus.NOT_FOUND, "이미 로그아웃한 사용자입니다."),
EMAIL_SEND_ERROR("U0006", HttpStatus.NOT_FOUND, "이메일 발송에 실패했습니다."),
EMAIL_AUTH_ERROR("U0007", HttpStatus.BAD_REQUEST, "유효하지 않은 인증 링크입니다."),
REQUIRE_EMAIL_AUTH("U0008", HttpStatus.UNAUTHORIZED, "이메일 인증이 필요한 사용자입니다.")
REQUIRE_EMAIL_AUTH("U0008", HttpStatus.UNAUTHORIZED, "이메일 인증이 필요한 사용자입니다."),
NON_VALID_USER_PASSWORD("U0009", HttpStatus.NOT_FOUND, "비밀번호가 올바르지 않습니다."),
DUPLICATE_USER_PASSWORD("U0010", HttpStatus.CONFLICT, "현재 비밀번호와 같은 비밀번호로 변경할 수 없습니다.")
;


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.narae.fliwith.exception.user;

import static com.narae.fliwith.exception.constants.UserExceptionList.DUPLICATE_USER_PASSWORD;

public class DuplicateUserPasswordException extends UserException{
public DuplicateUserPasswordException(){
super(DUPLICATE_USER_PASSWORD.getErrorCode(),
DUPLICATE_USER_PASSWORD.getHttpStatus(),
DUPLICATE_USER_PASSWORD.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.narae.fliwith.exception.user;

import static com.narae.fliwith.exception.constants.UserExceptionList.NON_VALID_USER_PASSWORD;

public class NonValidUserPasswordException extends UserException{
public NonValidUserPasswordException(){
super(NON_VALID_USER_PASSWORD.getErrorCode(),
NON_VALID_USER_PASSWORD.getHttpStatus(),
NON_VALID_USER_PASSWORD.getMessage());
}
}
103 changes: 103 additions & 0 deletions src/main/java/com/narae/fliwith/service/MailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
import jakarta.mail.internet.MimeMessage;
import jakarta.transaction.Transactional;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Slf4j
@RequiredArgsConstructor
Expand All @@ -25,6 +30,34 @@ public class MailService {
@Value("${email.server}")
private String server;

private final PasswordEncoder passwordEncoder;

private static final char[] rndAllCharacters = 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',

'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',
};


private static final char[] numberCharacters = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};

private static final char[] uppercaseCharacters = new char[] {
'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'
};

private static final char[] lowercaseCharacters = new char[] {
'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'
};


private MimeMessage createMessage(User user) throws MessagingException, UnsupportedEncodingException {
String content = "<div>"
+ "<h1> 안녕하세요. Fliwith 입니다</h1>"
Expand Down Expand Up @@ -55,4 +88,74 @@ public void sendMail(User user) {
throw new EmailSendException();
}
}

private String createPw() {
StringBuilder pwd = new StringBuilder();
SecureRandom random = new SecureRandom();
List<Character> passwordCharacters = new ArrayList<>();

int numberCharactersLength = numberCharacters.length;
passwordCharacters.add(numberCharacters[random.nextInt(numberCharactersLength)]);

int uppercaseCharactersLength = uppercaseCharacters.length;
passwordCharacters.add(uppercaseCharacters[random.nextInt(uppercaseCharactersLength)]);

int lowercaseCharactersLength = lowercaseCharacters.length;
passwordCharacters.add(lowercaseCharacters[random.nextInt(lowercaseCharactersLength)]);

int rndAllCharactersLength = rndAllCharacters.length;
for (int i = 0; i < 10; i++) {
passwordCharacters.add(rndAllCharacters[random.nextInt(rndAllCharactersLength)]);
}

Collections.shuffle(passwordCharacters);

for (Character character : passwordCharacters) {
pwd.append(character);
}
log.warn("randomPw={}", pwd.toString());
return pwd.toString();
}

public void tempoaryPassword(User user) {

String pw = createPw();
try{
MimeMessage mimeMessage = createTemporaryPasswordMessage(user, pw);
javaMailSender.send(mimeMessage);
String encodedPwd = passwordEncoder.encode(pw);
user.changePWd(encodedPwd);
}catch (Exception e){
e.printStackTrace();
throw new EmailSendException();
}
}

private MimeMessage createTemporaryPasswordMessage(User user, String initPassword)
throws MessagingException, UnsupportedEncodingException {
String content = "<head> <link rel='stylesheet' type='text/css'></head>\n"
+ "<div> <h1 style=\"text-align: center;\"> 안녕하세요. Fliwith 입니다</h1>\n"
+ " <br>\n"
+ "<div style=\"text-align: center; font-weight: 400;\">\n"
+ " 아래 임시 비밀번호를 로그인 시 사용해주세요.\n"
+ "<br>로그인 후 비밀번호를 꼭 변경해주세요.\n"
+ "</div>\n"
+ " <div style=\"padding-right: 30px; padding-left: 30px; margin: 32px 0 40px;\">\n"
+ " <table style=\"border-collapse: collapse; border: 0; background-color: #C1BAE5; height: 61px; table-layout: fixed; word-wrap: break-word; border-radius: 15px; margin-top: 10px; margin-left:auto; margin-right:auto;\"><tbody> <tr><td style = \"text-align: center; vertical-align: middle; font-size: 32px; color: #FFFFFF; font-weight: 500; padding-left: 109px; padding-right: 109px; padding-top: 11px; padding-bottom: 12px; text-align: center;\">\n"
+ initPassword+"\n"
+ " </td></tr></tbody></table></div>\n"
+ " </div>";


MimeMessage message = javaMailSender.createMimeMessage();
message.addRecipients(MimeMessage.RecipientType.TO, user.getEmail());
message.setSubject("Fliwith 임시 비밀번호:"); //메일 제목
message.setText(content, "utf-8", "html"); //내용, charset타입, subtype
message.setFrom(new InternetAddress(email,"Fliwith_Official")); //보내는 사람의 메일 주소, 보내는 사람 이름

log.info("message : " + message);
return message;
}


}
21 changes: 21 additions & 0 deletions src/main/java/com/narae/fliwith/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
import com.narae.fliwith.domain.User;
import com.narae.fliwith.dto.UserReq;
import com.narae.fliwith.dto.UserReq.EmailReq;
import com.narae.fliwith.dto.UserReq.NewPasswordReq;
import com.narae.fliwith.dto.UserReq.NicknameReq;
import com.narae.fliwith.dto.UserRes.ProfileRes;
import com.narae.fliwith.exception.security.InvalidTokenException;
import com.narae.fliwith.exception.user.AlreadyLogoutException;
import com.narae.fliwith.exception.user.DuplicateUserEmailException;
import com.narae.fliwith.exception.user.DuplicateUserNicknameException;
import com.narae.fliwith.exception.user.DuplicateUserPasswordException;
import com.narae.fliwith.exception.user.EmailAuthException;
import com.narae.fliwith.exception.user.LogInFailException;
import com.narae.fliwith.exception.user.NonValidUserPasswordException;
import com.narae.fliwith.repository.TokenRepository;
import com.narae.fliwith.repository.UserRepository;
import jakarta.servlet.ServletRequest;
Expand Down Expand Up @@ -123,4 +126,22 @@ public void updateSignupStatus(String auth){
user.completeSignup();
}

public void temporaryPassword(String email) {
User user = authService.authUser(email);
mailService.tempoaryPassword(user);
}

public void changePassword(String email, NewPasswordReq newPasswordReq) {
User user = authService.authUser(email);
if(newPasswordReq.getCurrentPassword().equals(newPasswordReq.getNewPassword())){
throw new DuplicateUserPasswordException();
}

if(passwordEncoder.matches(newPasswordReq.getCurrentPassword(), user.getPw())){
String encodedPassword = passwordEncoder.encode(newPasswordReq.getNewPassword());
user.changePWd(encodedPassword);
} else{
throw new NonValidUserPasswordException();
}
}
}

0 comments on commit 69d8429

Please sign in to comment.