[스프링부트 게시판] 37. 비밀번호 찾기

2022. 11. 1. 13:38·🚗 Backend Toy Project/스프링 부트 게시판
  • 사용자가 비밀번호를 기억하지 못할 경우 이메일을 통해 임시 비밀번호를 보내주고 기존 비밀번호를 해당 임시 비밀번호로 변경하여 로그인 할 수 있도록 구현해보았습니다.
  • 즉 임시 비밀번호가 발송되게 되면 기존 비밀번호로는 로그인 할 수 없습니다.
  • 참고로 프로젝트에서 메일 발송을 하기 위해선 해당 포스팅에 작성된 내용 말고도 추가적으로 진행해야되는 과정이 있지만 핵심내용은 아니라고 생각하여 해당 부분은 생략하였습니다.
  • 스프링부트 메일 전송에 대한 자세한 설명은 아래 링크에서 확인하실 수 있습니다.
 

SpringBoot에서 SMTP를 활용한 메일 전송 구현하기

📝 SMTP란? 스프링에서는 SMTP Relay를 이용한 메일 전송 기능을 제공하고 있습니다. 여기서 SMTP는 Simple Mail Transfer Protocol의 약자로, 전자 메일 전송 프로토콜을 의미합니다. SMTP Relay란 메일 서버 외

daegwonkim.tistory.com


📝 pom.xml

  • 우선 스프링부트 프로젝트에서 메일을 발송하기 위해 라이브러리를 추가해주었습니다.
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    <version>2.7.5</version>
</dependency>

📝 application.yml

  • 다음으로 application.yml 파일에 아래와 같은 설정을 해주었습니다.
spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: [발송 이메일]
    password: [앱 비밀번호]
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true

📝 user.js

  • 메일 발송은 ajax 요청을 통해 수행하였습니다.
find: function() {
    LoadingWithMask();

    let data = {
        username: $("#username").val(),
        email: $("#email").val()	
    };

    $.ajax({
        type: "POST",
        url: "/auth/find",
        data: JSON.stringify(data),
        contentType: "application/json; charset=utf-8"
    }).done(function(resp) {
        if (resp.status == 400) {
            if (resp.data.hasOwnProperty('valid_email')) {
                $('#valid_email').text(resp.data.valid_email);
                $('#email').focus();
            } else {
                $('#valid_email').text('');
            }

            if (resp.data.hasOwnProperty('valid_username')) {
                $('#valid_username').text(resp.data.valid_username);
                $('#username').focus();
            } else {
                $('#valid_username').text('');
            }

            closeLoadingWithMask();
        } else {				
            alert("임시 비밀번호가 발송되었습니다.");
            location.href = "/auth/loginForm";
        }
    }).fail(function(error) {
        console.log(error);
    });
}

📝 UserApiController

  • 위의 ajax 요청을 받는 컨트롤러는 아래와 같이 구현하였습니다.
package com.cos.blog.controller.api;

...

@RestController
@RequiredArgsConstructor
public class UserApiController {

	private final UserService userService;
	
	@PostMapping("/auth/find")
	public ResponseDto<?> find(@RequestBody SendTmpPwdDto dto) {
				
		if(!userRepository.existsByUsername(dto.getUsername()) || !Pattern.matches("^[a-zA-Z0-9+-\\_.]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$", dto.getEmail())) {
			Map<String, String> validResult = new HashMap<>();
			
			if(!userRepository.existsByUsername(dto.getUsername())) {
				validResult.put("valid_username", "존재하지 않는 사용자 이름입니다.");
			}
			if(!Pattern.matches("^[a-zA-Z0-9+-\\_.]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$", dto.getEmail())) {
				validResult.put("valid_email", "올바르지 않은 이메일 형식입니다.");
			}
			
			return new ResponseDto<>(HttpStatus.BAD_REQUEST.value(), validResult); 
		}
		
		userService.sendTmpPwd(dto);
		
		return new ResponseDto<Integer>(HttpStatus.OK.value(), 1); 
	}
}

📝 SendTmpPwdDto

package com.cos.blog.dto;

...

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class SendTmpPwdDto {

	private String username;
	private String email;
}

📝 UserService

  • 비즈니스로직을 수행할 UserSerivce는 아래와 같이 구현하였습니다.
package com.cos.blog.service;

...

@Service
@RequiredArgsConstructor
public class UserService {

	private final UserRepository userRepository;
	private final JavaMailSender javaMailSender;
	
	@Value("${spring.mail.username}")
	private String sendFrom;
	
	@Transactional
	public void sendTmpPwd(SendTmpPwdDto dto) {
		
        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 tmpPwd = "";

        // 문자 배열 길이의 값을 랜덤으로 10개를 뽑아 구문을 작성함
        int idx = 0;
        for (int i = 0; i < 10; i++) {
            idx = (int) (charSet.length * Math.random());
            tmpPwd += charSet[idx];
        }
		
        try {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setTo(dto.getEmail());
            message.setFrom(sendFrom);
            message.setSubject("baeg-won 임시 비밀번호 안내 이메일입니다.");
            message.setText("안녕하세요.\n"
            		+ "baeg-won 임시비밀번호 안내 관련 이메일 입니다.\n"
            		+ "임시 비밀번호를 발급하오니 블로그에 접속하셔서 로그인 하신 후\n"
            		+ "반드시 비밀번호를 변경해주시기 바랍니다.\n\n"
            		+ "임시 비밀번호 : " + tmpPwd);
            javaMailSender.send(message);
        } catch (MailParseException e) {
            e.printStackTrace();
        } catch (MailAuthenticationException e) {
            e.printStackTrace();
        } catch (MailSendException e) {
            e.printStackTrace();
        } catch (MailException e) {
            e.printStackTrace();
        }
		
        User user = userRepository.findByUsername(dto.getUsername()).orElseThrow(() -> {
            return new IllegalArgumentException("임시 비밀번호 변경 실패: 사용자 이름을 찾을 수 없습니다.");
        });
		
        user.setPassword(encoder.encode(tmpPwd));
	}
}
  • JavaMailSender는 스프링부트의 starter-mail이 제공하는 인터페이스로 setTo(), setFrom(), setTitle(), setText()와 같은 메소드를 제공합니다.

📝 findForm

  • 뷰 페이지는 아래와 같이 구현하였습니다.
<div class="container" align="center">
	<div class="form-title">Reset your password</div>
	<div class="form-style">
		<form>
			<div align="left" style="word-spacing: -4px;">Enter your user account's verified email address and we will send you a password reset link.</div><br>
			<div class="form-group" align="left">
				<label for="username">Username</label> <input type="text" class="form-control" placeholder="Enter username" id="username">
			</div>
			<p class="valid-text" id="valid_username" align="left"></p>
			<div class="form-group" align="left">
				<label for="email">Email</label> <input type="email" class="form-control" placeholder="Enter email" id="email">
			</div>
			<p class="valid-text" id="valid_email" align="left"></p>
		</form>
		<div align="right">
			<button id="btn-find" class="btn btn-find"><i class="fa-solid fa-check"></i> Send password reset email</button>
		</div>
	</div>
</div>

📝 Result

findForm.jsp

 


💡 알게 된 점

  • SMTP의 개념과 임시 비밀번호가 발급되는 과정

 

GitHub - Daegwon-Kim/SpringBoot-JPA-Blog

Contribute to Daegwon-Kim/SpringBoot-JPA-Blog development by creating an account on GitHub.

github.com

 

저작자표시 (새창열림)

'🚗 Backend Toy Project > 스프링 부트 게시판' 카테고리의 다른 글

[스프링부트 게시판] 36. 관리자 페이지 - 게시글 통계  (0) 2022.10.26
[스프링부트 게시판] 35. 관리자 페이지 - 회원 관리  (0) 2022.10.24
[스프링부트 게시판] JPA Specification을 통해 쿼리 조건 다루기  (0) 2022.10.06
[스프링부트 게시판] 34. 사용자 프로필 이미지 추가  (0) 2022.09.27
[스프링부트 게시판] 33. 댓글 알림 기능  (1) 2022.09.23
'🚗 Backend Toy Project/스프링 부트 게시판' 카테고리의 다른 글
  • [스프링부트 게시판] 36. 관리자 페이지 - 게시글 통계
  • [스프링부트 게시판] 35. 관리자 페이지 - 회원 관리
  • [스프링부트 게시판] JPA Specification을 통해 쿼리 조건 다루기
  • [스프링부트 게시판] 34. 사용자 프로필 이미지 추가
Baeg-won
Baeg-won
  • Baeg-won
    좋았다면 추억이고 나빴다면 경험이다.
    Baeg-won
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 🍃 Spring, Spring Boot
        • 스프링 프레임워크 기초
        • 스프링 핵심 원리 - 기본편
        • 자바 ORM 표준 JPA 프로그래밍 - 기본편
        • 스프링 MVC
        • 실전! 스프링 부트와 JPA 활용1 - 웹 애플리..
      • 🥑 Web Technoloy
      • 🚗 Backend Toy Project
        • 스프링 부트 게시판
        • Photogram
        • Baeg-won Clothing Gallery
      • 🥇 Problem Solving
        • Breadth-First Search
        • Depth-First Search
        • Backtracking
        • Simulation
        • Two-pointer
        • Binary Search
        • Greedy
        • Dynamic Programming
        • Minimum Spanning Tree
        • Dijkstra
        • Floyd warshall
      • ☕ Java
        • 명품 자바 에센셜
        • Applications
      • 🍦 JavaScript
        • JavaScript 기초
      • 🐧 Linux
        • 이것이 리눅스다(CentOS 8)
      • 📟 Database
        • 혼자 공부하는 SQL
      • 🧬 Data Structure
      • 🎬 HTML
      • 🎤 Tech Interview
      • 📌 etc
        • Unity 2D Raising Jelly Game
        • C++
        • 영어 쉐도잉
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Baeg-won
[스프링부트 게시판] 37. 비밀번호 찾기
상단으로

티스토리툴바