토이 프로젝트를 하다가 회원가입과 로그인, 로그아웃 기능을 만들게 되었는데
그때 사용했던 개념들을 정리하고자 한다
먼저 이메일을 통해서 회원가입을 했던 과정을 정리한다
- 개발환경
spring boot : 2.5.2
java : 16
maven : 3.6.3
- 의존성
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
|
cs |
thymeleaf 는 이메일 보낼때 적을 내용을 담고 있다
(java 에서 로직처리한 데이터를 전달받아 랜더링하기 위해서 사용됨)
- Gmail 설정하기
: 실제 서비스 운영시에는 Gmail 이 아닌 다른 메일 서버를 사용하겠지만 (보내는 양에 한도가 있기 때문)
여기선 Gmail 을 썼다
그래서 https://www.siteground.com/kb/gmail-smtp-server/ 에 적힌 내용을 기반으로 application.properties 를 다음과 같이 작성했다
application.properties
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=<개인-gmail-id>
spring.mail.password=<개인-gmail-password>
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
|
cs |
* Spring Boot 에서 Mail 을 보내기 위한 사전지식
: Spring Boot 를 통해서 이메일을 보내기 위해 Spring 에서 제공하는 인터페이스와 클래스들에 대해서 어느정도 사전지식이 필요하다
기본적으로 제공되는 인터페이스 및 클래스들은 다음과 같다
1) MailSender 인터페이스
: 단순한 이메일을 보내기위한 기본 기능들을 제공하는 최상위 레벨의 인터페이스다
2) JavaMailSender 인터페이스
: MailSender 인터페이스의 하위 인터페이스 이며, 이 인터페이스는 MIME 메시지를 지원하고 대체로 MimeMessageHelper 클래스와 같이 쓰인다 (아래 서술할 MimeMessagePreparator 와 같이 쓰임)
3) JavaMailSenderImpl 클래스
: 이름에서 알 수 있듯이 JavaMailSender 인터페이스의 구현 클래스이다.
4) SimpleMailMessage 클래스
: 단순한 메일 보내는데 쓰인다 (단순 텍스트만 보낼때 사용)
5) MimeMessagePreparator 인터페이스
: MIME 메시지 준비를 위해서 필요한 콜백 인터페이스를 제공한다
6) MimeMessageHelper 클래스
: MIME 메시지 생성을 위해 쓰이는 클래스다
이미지, 파일, 텍스트 등을 html 형식으로 제공한다
* MIME 이란 단순 텍스트 뿐 아니라 다른 여러 바이너리 파일을 메일에 첨부할때 쓰인다.
* 이메일로 회원가입하는 코드들
0) SecurityConfig
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**")
.permitAll()
.anyRequest()
.authenticated();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
|
cs |
1) Controller
@RestController
@RequestMapping("/api/auth")
@AllArgsConstructor
public class AuthController {
private final AuthService authService;
@PostMapping("/signup")
public ResponseEntity<String> signup(@RequestBody RegisterRequest registerRequest) {
authService.signup(registerRequest);
return new ResponseEntity<>("회원가입 완료", HttpStatus.OK);
}
@GetMapping("accountVerification/{token}")
public ResponseEntity<String> verifyAccount(@PathVariable String token) {
authService.verifyAccount(token);
return new ResponseEntity<>("계정 활성화가 성공적으로 되었습니다.", HttpStatus.OK);
}
}
|
cs |
RegisterRequest 는 유저로 부터 이메일과 비밀번호를 받는 DTO 이다
이메일을 받은 유저가 링크를 받았을때 그 링크를 클릭하면 그 때 활성화된 계정으로 바뀌도록
verifyAccount 라는 메소드를 추가했다.
2) Service
2-1. AuthService.java
@Service
@Slf4j
@AllArgsConstructor
public class AuthService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final VerificationTokenRepository verificationTokenRepository;
private final MailContentBuilder mailContentBuilder;
private final MailService mailService;
@Transactional
public void signup(RegisterRequest registerRequest) {
User user = new User();
user.setEmail(registerRequest.getEmail());
user.setPassword(encodePassword(registerRequest.getPassword()));
user.setEnabled(false);
userRepository.save(user);
String token = generateVerificationToken(user);
String link = Constants.ACTIVATION_EMAIL + "/" + token;
String message = mailContentBuilder.build(link);
mailService.sendMail(new NotificationEmail("계정 활성화를 실행해주세요.", user.getEmail(), message));
}
private String generateVerificationToken(User user) {
String token = UUID.randomUUID().toString();
VerificationToken verificationToken = new VerificationToken();
verificationToken.setToken(token);
verificationToken.setUser(user);
verificationTokenRepository.save(verificationToken);
return token;
}
private String encodePassword(String password) {
return passwordEncoder.encode(password);
}
public void verifyAccount(String token) {
Optional<VerificationToken> verificationTokenOptional = verificationTokenRepository.findByToken(token);
verificationTokenOptional.orElseThrow(() -> new CustomException("잘못된 토큰"));
fetchUserAndEnable(verificationTokenOptional.get());
}
@Transactional
public void fetchUserAndEnable(VerificationToken verificationToken) {
String email = verificationToken.getUser().getEmail();
User user = userRepository.findByEmail(email).orElseThrow(() -> new CustomException("유저를 찾을 수 없음 " + email));
user.setEnabled(true);
userRepository.save(user);
}
}
|
cs |
회원가입시에 이메일 받은 유저가 이메일 링크를 클릭해야만 계정 활성화를 하도록 했다.
그래서 signup 메소드에서 먼저 userRepository.save(user) 로 유저를 DB 에 저장한 이후
이메일에 verificationToken 이라는 검증 토큰을 생성한후 이메일로 보내게 했다.
이메일에서 받은 검증 토큰은 UUID 를 통해서 랜덤값을 만들었다.
검증은 verifyAccout 메소드에서 한다.
그리고 최종적으로 계정활성화는 fetchUserAndEnable 메소드에서 실행한다.
2-2. MailService.java
@Service
@Slf4j
@AllArgsConstructor
public class MailService {
private final JavaMailSender mailSender;
@Async
void sendMail(NotificationEmail notificationEmail) {
MimeMessagePreparator messagePreparator = mimeMessage -> {
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
messageHelper.setFrom("보내는 사람 이메일 ");
messageHelper.setTo(notificationEmail.getRecipient());
messageHelper.setSubject(notificationEmail.getSubject());
messageHelper.setText(notificationEmail.getBody(), true);
};
try {
mailSender.send(messagePreparator);
log.info("활성화 메일이 보내졌다");
} catch (MailException e) {
log.error(String.valueOf(e));
throw new CustomException("메일을 여기로 보내는 중 에러 발생 : " + notificationEmail.getRecipient());
}
}
}
|
cs |
위에서 언급한 JavaMailSender 와 MimeMessagePreparator, MimeMessageHelper 를 같이 사용하였다.
NotificationEmail 은 이메일 전송시에 담을 제목, 수신자, 이메일 내용 등을 담는 DTO 이다.
3) 메일 내용
AuthService.java 에 보면 회원가입 메소드에 String message = mailContentBuilder.build(link) 가 있다
이는 앞서 설정한 Thymeleaf 뷰 템플릿을 통해서 이메일에 작성할 html 코드를 쓰기 위함이다
MailContentBuilder.java
@Service
@AllArgsConstructor
public class MailContentBuilder {
private final TemplateEngine templateEngine;
String build(String message) {
Context context = new Context();
context.setVariable("link", message);
return templateEngine.process("mailTemplate", context);
}
}
|
cs |
뷰 템플릿에 지정할 변수 link 를 정의했다.
그리고 뷰 템플릿의 파일 이름은 mailTemplate.html 이다
mailTemplate.html
<!DOCTYPE html>
<html lang="ko" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>이메일 인증 링크</title>
</head>
<body>
<span>계정 활성화를 위해서 아래의 인증 링크를 클릭해주세요.</span><br>
<a th:href="${link}">인증 링크</a>
</body>
</html>
|
cs |
이후 메일을 실제로 보내게 되면 다음과 같이 이메일을 받을 수 있게 된다.
- References
1) Guide to Spring Email : https://www.baeldung.com/spring-email
2) Spring Boot 이메일 전송 : https://victorydntmd.tistory.com/342
'Spring' 카테고리의 다른 글
Spring Cloud Eureka 와 기본 REST API (0) | 2021.09.14 |
---|---|
Spring Boot 와 JWT 로 로그인하기 (0) | 2021.07.06 |
Spring Cloud Netflix Eureka (0) | 2021.07.05 |
Spring Cloud 와 Microservice 란 (0) | 2021.07.01 |
Swagger 를 통한 REST API 문서화 (0) | 2021.04.30 |