본문 바로가기

Back-End/Spring boot

[JAVA][Spring] 로그인, 회원 가입 (1)

~ 목차 ~

로그인, 회원가입 기능을 만들고 난 후

로그인할 때 비밀번호가 기억이 나지 않을 때 본인인증을 통한 비밀번호 변경 기능 추가하기

 

1. 회원가입 기능

   + id 중복체크 기능

   + 비밀번호 입력 시 눈모양 클릭하면 입력 내용 보이기 기능

2. 로그인 기능

   + 비밀번호 입력 시 눈모양 클릭하면 입력 내용 보이기 기능

3. 본인 인증 기능

4. 비밀번호 변경 기능


[로그인] , [회원가입]

 

1. User.java (Entity만들기)

 

@Entity
@Data
public class User implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String email;
	private String pwd;
        private String newPassword;
	private String name;
	private Integer phone;
	private Date creDate;
	private Integer count;
	private UserRole role;

	public enum UserRole { //열거형 값
		CUSTOMER, // 일반 고객0
		ADMIN // 관리자1
	}

	public String getRole() {
		return role.name(); // 열거형 값의 이름을 문자열로 반환
	}

}

 

※ @Data : Data는 접근불가능하게 설정되므로 set, get 메소드를 만들어 줘야하는데 @Data를 넣으면 set, get 메소드를  자동으로 만들어줌. 즉, toString()를 Override하고 있음

 

2. UserRepository.java 만들기

 

public interface UserRepository extends JpaRepository<User, Long> {
  public User findByEmailAndPwd(String email, String pwd);
  public User findByEmail(String email);
  public User findById(long id);
  List<User> findByEmailAndNameAndPhone(String email,String name, Integer phone);
}

 

※ extends JpaRepository<User, Long> : JPA Repository 상속받음 , User 테이블의 id를 Long형태로 가져옴

List<User> findByEmailAndNameAndPhone(String email,String name, Integer phone);

    : User 엔티티에서 email, name, 그리고 phone 필드가 주어진 값과 일치하는 레코드를 모두 찾아내기

 

3. UserController.java 만들기

 

@Controller
public class UserController {
	@Autowired
	UserRepository userRepository;
    
    @Autowired
	PasswordEncoder passwordEncoder;
    
    //회원가입
    @GetMapping("/signup")
	public String signup(Model model) {
		return "signup";
	}

	@PostMapping("/signup")
	public String signupPost(@ModelAttribute User user,
			@RequestParam(value = "isAdmin", required = false) boolean isAdmin) {
		String userPwd = user.getPwd();
		String encodePwd = passwordEncoder.encode(userPwd); //비밀번호 암호화
		user.setPwd(encodePwd);
		user.setCreDate(new Date());

		// 사용자 역할 설정 (관리자 or 고객)
		User.UserRole userRole = isAdmin ? User.UserRole.ADMIN : User.UserRole.CUSTOMER;

		// 사용자 정보 저장
		user.setRole(userRole);
		user.setCoinDate(new Date(0));
		userRepository.save(user);

		return "redirect:/";
	}
    
    //id중복체크
    @GetMapping("/email-check")
	@ResponseBody
	public String emailCheck(@ModelAttribute User user) {
		String email = user.getEmail();

		User result = userRepository.findByEmail(email);

		if (result != null) { // 값 있음=아이디가 있음=>가입 불가
			return "가입불가";
		} else { // 값 없음=아이디가 없음=>가입 가능
			return "가입가능";
		}
	}
    
    //로그인
    @GetMapping("/signin")
	public String signin() {
		return "signin";
	}

	@PostMapping("/signin")
	public String signinPost(@ModelAttribute User user, Model model) {
		User dbUser = userRepository.findByEmail(user.getEmail());

		// 오류
		if (dbUser == null) {
			model.addAttribute("error", "이메일 또는 비밀번호가 일치하지 않습니다.");
			return "signin";
		}
		String encodedPwd = dbUser.getPwd(); //등록된 암호화비밀번호
		String userPwd = user.getPwd();		 //입력한 비밀번호
		boolean isMatch = passwordEncoder.matches(userPwd, encodedPwd);

		if (isMatch) {
			// 로그인 성공한 경우 user_info 세션에 넣기
			session.setAttribute("user_info", dbUser);

			return "redirect:/";
		} else {
			model.addAttribute("error", "이메일 또는 비밀번호가 일치하지 않습니다.");
			return "signin";
		}
	}
}

 

4. signup.html / signin.html 만들기

 

 1)signup.html (id 중복체크 기능 추가)

 

<!DOCTYPE html>
<html lang="en">

<head th:replace="common/head"></head>

<body>
  <div th:replace="common/header"> </div>
  <nav th:replace="common/nav"></nav>
  <div class="title">
    <h1>회원가입</h1>
  </div>
  <div class="signupForm">
    <div class="container mt-5">
      <div class="row">
        <form method="post" action="/signup" id="realsignupForm">
          <div class="mb-3">
            <label for="email">Email:</label>
            <input type="email" class="form-control" id="email" name="email" pattern="[a-z0-9._%+-]+@[a-z]+\.[a-z]{2,}$"
              title=" 정확한 이메일 주소를 입력해주세요" placeholder="ex.daram@dotori.com" required>
            <button class="btn btnn-primary" type="button" onclick="checkEmail()">중복확인</button>
          	<span id="duplicateResult"></span>
          </div>
          <div class="mb-3">
            <label for="pwd">Password:</label>
            <input type="password" class="form-control" id="pwd" name="pwd" pattern="(?=.*\d)(?=.*[a-zA-Z]).{8,}"
              title="영문대소문자/숫자로 이루어진 최소 8글자의 비밀번호를 입력하세요" placeholder="영문대소문자/숫자로 이루어진 최소 8글자의 비밀번호" required>
            <i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>
          </div>
          <div class="mb-3">
            <label for="name">Name:</label>
            <input type="text" class="form-control" id="name" name="name" pattern="^[a-zA-Z가-힣]+$"
              title="올바른 이름을 입력하세요 ex.홍길동" placeholder="이름" required>
          </div>
          <div class="mb-3">
            <label for="name">Phone:</label>
            <input type="text" class="form-control" id="phone" name="phone" pattern="[0-9]{10,11}"
              title="10-11자리의 숫자를 '-' 없이 입력하세요" placeholder="휴대전화번호('-'기호 제외 10~11자리)" required>
          </div>
          <div class="mb-3 form-check">
            <input type="checkbox" class="form-check-input" id="isAdmin" name="isAdmin">
            <label class="form-check-label" for="isAdmin">관리자</label>
          </div>
          <div class="d-grid gap-2">
            <button class="btn btnn-primary" id="signup" style="width : 250px;">가입하기</button>
          </div>
        </form>
      </div>
    </div>
  </div>

<script>
        // id중복체크
        async function checkEmail() {
          const email = document.querySelector("[name=email]").value;
          const response = await fetch(`/email-check?email=${encodeURIComponent(email)}`);
          const result = await response.text();

          // 중복 확인 결과에 따라 메시지 표시
          const duplicateResultElement = document.getElementById("duplicateResult");

          if (result == "가입불가") {
            duplicateResultElement.textContent = "중복된 Email입니다.";
            duplicateResultElement.style.color = "red";
            isEmailValid = false;
    
          } else if (result == "가입가능") {
            duplicateResultElement.textContent = "사용 가능한 Email입니다.";
            duplicateResultElement.style.color = "green";
            isEmailValid = true;
            
          }
          updateSignupButtonState();
        }
        
        // 비밀번호 보이기표시
        function togglePasswordVisibility() {
          var $passwordInput = $('#pwd'); // ID를 사용하여 비밀번호 입력란을 선택
          if ($passwordInput.attr('type') === 'password') {
            $('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
            $passwordInput.attr('type', 'text');
          } else {
            $('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
            $passwordInput.attr('type', 'password');
          }

        }
      </script>
    
    <div th:replace="common/footer" style="margin-top: 1rem;">
    </div>

</body>

</html>

 

 2)signin.html

 

<!DOCTYPE html>
<html lang="en">

<head th:replace="common/head"></head>

<body>
  <div th:replace="common/header"></div>
  <nav th:replace="common/nav"></nav>
  <div class="title">
    <h1>로그인</h1>
  </div>
  <div class="container mt-5">
    <div class="row">
      <form method="post" action="/signin">
        <div class="mb-3 input-group flex-nowrap">
          <span class="input-group-text">💻</span>
          <input type="email" class="form-control" id="email" name="email" placeholder="email" title="이메일 형식이어야 합니다" required>
        </div>
        <div class="mb-3 input-group flex-nowrap">
          <span class="input-group-text">🔒</span>
          <input type="password" class="form-control" id="pwd" name="pwd" placeholder="password" required>
          <i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>
        </div>
        <div th:if="${error}" class="alert alert-danger">
          <p th:text="${error}"></p>
        </div>
        <div class="d-grid gap-2">
          <button class="btn btn-primary" id="signin">로그인</button>
        </div>
        <div class="d-grid gap-2">
          <a class="pwdforget" id="pwdforget" href="/pwdforget">비밀번호가 기억나지 않는다면?</a>
        </div>
      </form>
    </div>
  </div>

  <script>
  	//비밀번호 눈 클릭하면 보이기
    function togglePasswordVisibility() {
      var $passwordInput = $('#pwd');
      if ($passwordInput.attr('type') === 'password') {
          $('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
          $passwordInput.attr('type', 'text');
      } else {
          $('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
          $passwordInput.attr('type', 'password');
      }
  	}
  </script>
</body>

</html>

결과물

로그인 화면
회원가입화면

본인 인증, 비밀번호 변경 기능은 다음 글을 참고하세요~ 

728x90