성공 화면!!
전체 회원가입 과정
- 정보 입력받기
- 중복 형식 테스트 → 실패 시 리턴
- 토큰 발행, 토큰도 객체에 넣어서 레디스에 임시저장
- 메일 전송(토큰 포함된 링크)
- 사용자 메일 입력
- 메일 회신에서 온 토큰과 레디스에서 뽑은 토큰 일치 확인 → 불일치 시 리턴
- 토큰 일치 시 레디스 정보 DB 저장
- 회원가입 완료!!
1. bulid.gradle 에 의존성 입력
//naver mail
implementation 'org.springframework.boot:spring-boot-starter-mail:3.0.5'
implementation 'com.sun.mail:jakarta.mail:2.0.1'
2. 메일 config 파일 작성
@Configuration
@PropertySource("classpath:application.yml")
@ConfigurationProperties(prefix = "spring.mail")
@Getter
@Setter
@ToString
@Slf4j
public class MailConfig {
private String username;
private String password;
private int port;
private Properties properties;
@Bean
public JavaMailSender javaMailService() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
//
javaMailSender.setHost("smtp.naver.com");
javaMailSender.setUsername(username); // 네이버 아이디
javaMailSender.setPassword(password); // 네이버 비밀번호
javaMailSender.setPort(port); // 메일 인증서버 포트
javaMailSender.setJavaMailProperties(properties);
return javaMailSender;
}
}
yml 파일도 작성
mail:
host: smtp.naver.com
port: 465
username: ${SPRING_MAIL_USERNAME}
password: ${SPRING_MAIL_PASSWORD}
properties:
mail:
smtp:
auth: true
starttls:
enable: true
ssl:
enable: true
trust: smtp.naver.com
debug: true
3. controller 작성
@Slf4j
@RestController
@RequestMapping("/api/auth/mail/naver")
@RequiredArgsConstructor
public class MailController {
private final MailService mailService;
private final RedisService redisService;
private final MemberService memberService;
//회원가입
@PostMapping("/signup")
public ResponseEntity<ApiResponse<?>> signup(@RequestBody MemberReqDtoByMail memberReqDtoByMail) throws Exception {
//email 형식 인증 추가
if(!memberService.checkEmailForm(memberReqDtoByMail.getEmail())){
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.error(ErrorType.INVALID_EMAIL_FORM));
}
if(!memberService.checkDuple(memberReqDtoByMail.getEmail())){
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.error(ErrorType.INVALID_EMAIL_DUPLE));
}
String token = UUID.randomUUID().toString();
memberReqDtoByMail.setToken(token);
//redis 저장
redisService.setValues(memberReqDtoByMail.getEmail(), memberReqDtoByMail);
//메일 전송
mailService.sendMail(token, memberReqDtoByMail.getEmail());
return ResponseEntity
.status(HttpStatus.OK)
.body(ApiResponse.success(SuccessType.SEND_EMAIL, SuccessType.SEND_EMAIL.getMessage()));
}
//토큰 검증 및 인증
@GetMapping("/verify")
public ResponseEntity<ApiResponse<Object>> verifyEmail( @RequestParam String email, String token){
//토큰 일치시 DB 저장
if(mailService.checkToken(email, token)){
SimpleMemberRespDto response = memberService.addMember(redisService.getValues(email, MemberReqDtoByMail.class));
return ResponseEntity
.status(HttpStatus.OK)
.body(ApiResponse.success(SuccessType.SUCCESS_CREATE, response));
}else{
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.error(ErrorType.INVALID_TOKEN, ErrorType.INVALID_TOKEN.getMessage()));
//
}
}
}
4. service 작성
@Service
@RequiredArgsConstructor
public class MailService {
private final JavaMailSender javaMailSender;
private final RedisService redisService;
private MimeMessage createMessage(String token, String email) throws MessagingException, UnsupportedEncodingException {
MimeMessage message = javaMailSender.createMimeMessage();
message.addRecipients(MimeMessage.RecipientType.TO, email);// 보내는 대상
String verificationUrl = "http://localhost:8080/api/auth/mail/naver/verify?email=" + email + "&token=" + token;
message.setSubject("Artify 회원가입 이메일 인증");// 제목
String body = "<div>"
+ "<h1> 안녕하세요. 인증메일 입니다</h1>"
+ "<br>"
+ "<p>아래 링크를 클릭하면 이메일 인증이 완료됩니다.<p>"
+ "<a href='"+ verificationUrl+ "'>인증 링크</a>"
+ "</div>";
message.setText(body, "utf-8", "html");// 내용, charset 타입, subtype
// 보내는 사람의 이메일 주소, 보내는 사람 이름
message.setFrom(new InternetAddress("jjhhh6845@naver.com", "Artify_Admin"));// 보내는 사람
return message;
}
public void sendMail(String token, String email) throws MessagingException, UnsupportedEncodingException {
MimeMessage mimeMessage = createMessage(token, email);
javaMailSender.send(mimeMessage);
}
public boolean checkToken(String email, String token) {
MemberReqDtoByMail dto = redisService.getValues(email, MemberReqDtoByMail.class);
String originToken = (dto.getToken());
if(token.equals(originToken)){
return true;
}else{
return false;
}
}
}
고민 사항들
- 토큰 발급 후 다시 돌아올 때 까지 어디에 저장 할 것 인가
→ 레디스에 임시 저장함
→ 토큰만 저장, 모든 내용 저장
→ 직렬화, 역직렬화 필요(object Mapper)
public void setValues(String key, Object data) throws JsonProcessingException { String json = objectMapper.writeValueAsString(data); ValueOperations<String, Object> values = redisTemplate.opsForValue(); values.set(key, json); }
- 25 port → 메일 port 및 설정 오류
- 아이디 비번 오류(실제로 일치함) → 해당 서비스 허용 안함
- java mail sender 가 인터페이스인데 생성자 주입이 되는가
→ impl 로 객체 주입 해주고 각자 세팅해준다음 @bean으로 등록 해주면 DI 완료
'web 개발 > auth' 카테고리의 다른 글
SpringSecurity 인증 방식 (0) | 2024.06.29 |
---|