728x90
※본 포스트는 이전 포스트와 이어집니다.※
지난 번에...
가상의 시나리오들 중 3번을 제외한 나머지들은 개발하였습니다.
비밀번호 변경을 위한 메일 발송을 하기 위해 몇 가지 세팅을 해야합니다.
준비 과정
먼저 지메일(gmail)를 사용하여 이메일을 발송할 것이기에
앱 비밀번호를 추가해줘야합니다.
앱 비밀번호는 2단계 인증을 사용해야하지만 가능한 기능입니다.
(보안 탭에서 찾을 수 있습니다.)
기기 선택을 메일을 보낼 기기로 선택하고 생성한 후, 도움말에서 나온 대로 설정해주면 사용 가능합니다.
그후, dependency를 추가합니다.
implementation 'org.springframework.boot:spring-boot-starter-mail'
dependency를 추가하고 난 후에는 application.yml 혹은 properties에 SMTP를 설정합니다.
spring:
mail:
host: smtp.gmail.com
port: 587
username: {앱 비밀번호를 발급받은 이메일}
password: {앱 비밀번호}
properties:
mail:
smtp:
auth: true
starttls:
enable: true
이메일 발송 및 유효
이메일을 송신하기 위한 작업이기 때문에 회원가입 코드를 수정하였습니다.
javax.mail.internet.* 에 있는 라이브러리를 사용하여 해당 이메일이 유효한 이메일인지 판단하도록 하였습니다.
@RequiredArgsConstructor
@Service
public class MailService {
private final JavaMailSender javaMailSender;
private final SpringTemplateEngine templateEngine;
@Value("${spring.mail.username}")
private String senderEmail;
public void sendMail(Long id, String email) {
try {
MimeMessage mimeMailMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
mimeMessageHelper.setSubject("[Workshop6349 Security]");
mimeMessageHelper.setFrom(senderEmail);
mimeMessageHelper.setTo(email);
Context context = new Context();
context.setVariable("id", id);
String html = templateEngine.process("emailTemplate", context);
mimeMessageHelper.setText(html, true);
javaMailSender.send(mimeMailMessage);
} catch (MessagingException e) {
e.printStackTrace();
}
}
public boolean isValidEmailAddress(String email) {
boolean result = true;
try {
InternetAddress emailAddress = new InternetAddress(email);
emailAddress.validate();
} catch (AddressException e) {
result = false;
}
return result;
}
}
그리고 이메일을 발송할 수 있도록 service 클래스를 생성하였습니다.
※ 주의! isValidEmailAddress 메소드는 해당 이메일의 존재 유무는 알지 못합니다. 단지, 정규표현식으로 하여 올바른 이메일 방식인지 유무를 묻는 것 뿐입니다. ※
private final MailService mailService;
@Transactional
public void register(UserRequestDto userRequestDto) {
String email = userRequestDto.getEmail();
String password = userRequestDto.getPassword();
if (mailService.isValidEmailAddress(email)) {
String msg = email + " is not valid email!";
throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, msg);
}
if (userRepository.existsByEmail(email)) {
String msg = "user " + email + " is already exists";
throw new HttpClientErrorException(HttpStatus.CONFLICT, msg);
}
String salt = securityService.getSalt();
String hashedPassword = securityService.encrypt(password + salt);
userRepository.save(User.builder()
.email(email)
.password(hashedPassword)
.salt(salt)
.build());
}
public void sendChangePasswordEmail(String token) {
UserResponseDto userResponseDto = findByToken(token);
mailService.sendMail(userResponseDto.getId(), userResponseDto.getEmail());
}
현재 비밀번호 변경은 AccessToken이 있어야지만 변경가능하도록 설계되어 있습니다.
AccessToken없이도 변경하도록 하는 방법은 회원가입 코드를 응용하여
- 이메일이 유효한지 확인
- 회원으로 저장되어 있는 지 확인
- 해당 이메일로 비밀번호 변경 이메일 전송
@RequiredArgsConstructor
@Controller
public class EmailController {
private final UserService userService;
private final SecurityService securityService;
@GetMapping("/change-password/{id}")
public ModelAndView passwordChangeDirect(@PathVariable Long id) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("passwordTemplate");
UserResponseDto userResponseDto = userService.findById(id);
modelAndView.addObject("email", userResponseDto.getEmail());
return modelAndView;
}
@PostMapping("/password")
public String changePassword(String email, String password) {
User user = userService.findByEmail(email);
String salt = securityService.getSalt(); // salt 도 변경
if (user.setPassword(securityService.encrypt(password + salt))) {
return "passwordChangeSuccess";
}
return "passwordChangeFailed";
}
}
html (타임리프 엔진)
테스트
이상입니다.
'Spring > 괴발개발' 카테고리의 다른 글
[괴발개발] 덕지덕지 - 기본 페이지 및 엔티티 설계 (0) | 2022.03.30 |
---|---|
[괴발개발] Remote Note (0) | 2022.03.22 |
[괴발개발] REST API - 인증 (0) | 2022.03.02 |
[괴발개발] TODO 웹 개발 노트 - 도커(Docker) 배포 (0) | 2022.02.21 |
[괴발개발] TODO 웹 개발 노트 - 예외처리 및 완료 (0) | 2022.02.20 |