스프링 미니 프로젝트 - JPA로 간단한 로그인 기능 구현

Zyoon·2025년 5월 22일

미니프로젝트

목록 보기
9/35
post-thumbnail

📘JPA 사용하여 로그인 기능 구현


0. 준비

1. Entity

  • Entity 는 회원가입 기능에 사용한 Entity 를 그대로 사용한다.
  • email 값이 로그인의 할 때의 ID로 사용된다.
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String username;
		//로그인 정보의 ID 역할
    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

2. DTO

  • email, password를 요청받는다. Getter 와 생성자를 추가해준다.
  • Controller 부분에서 유효성 검사를 위해 Validation 을 사용했다
    • NotBlank : 값이 null 이거나 공백일경우 예외 처리
  • ResponseDto로 넘기는 값은 id 하나이지만, 유지보수를 원활히 하기 위해 만들었다.
//Client로 부터 받는 Dto
@Getter
public class LoginRequestDto {

    @NotBlank(message = "이메일을 입력해주세요.")
    private final String email;

    @NotBlank(message = "비밀번호를 입력해주세요.")
    private final String password;

    public LoginRequestDto(String email, String password) {
        this.email = email;
        this.password = password;
    }
}

//세션 저장을 위한 Dto
//유저의 id값을 반환하는 Dto도 만들어준다. 
@Getter
public class LoginResponseDto 
    private final Long id;
    public LoginResponseDto(Long id) {
        this.id = id;
    }
}

3. Repository

  • 기존 Repository에 메서드를 추가해준다.
  • findByEmail : User 테이블에서 email 필드로 조회를한다. 이 메서드는 이름만으로 자동 구현된다.
  • null 방지를 위해 Optional 타입으로 반환된다.
public interface UserRepository extends JpaRepository<User, Long> {
	Optional<User> findByEmail(String email);
}

4. Service

  • 전달받은 email 값을 통해 유저 정보를 DB 에서 찾아 반환한다.
  • findByEmail 메서드의 반환값은 Optional 타입이기 때문에 null 예외처리를 바로 해준다.
  • 전달받은 비밀번호와 DB 안의 비밀번호를 비교해 일치하면 userId 값을 반환한다. (불일치 예외처리)
public LoginResponseDto login(LoginRequestDto requestDto) {
		//DB에서 Email로 User 정보 반환
    User user = userRepository.findByEmail(requestDto.getEmail())
            .orElseThrow((
            )->new ResponseStatusException(HttpStatus.NOT_FOUND, "유저 정보 없음"));
		//비밀번호 확인
    if(!user.getPassword().equals(requestDto.getPassword())){
        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "비밀번호 불일치");
    }
    //객체 반환
    return new LoginResponseDto(user.getId());
}

5. Controller

  • /users/login 경로로 Post 요청을 받는다.
  • 클라이언트가 보낸 로그인 요청 JSON을 LoginRequestDto 객체로 매핑.
  • @Valid를 사용해 해당 DTO의 유효성 검사를 수행함.
  • getSession() 을 통해 현재 로그인 상태인지(세션에 userId 값이 있는지) 확인한다. (존재하면 예외처리)
  • HttpServletRequest 을 사용해 Service 에서 전달받은 userId 값을 세션에 저장한다.
@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @PostMapping("/login")
    public ResponseEntity<String> login(@Valid @RequestBody LoginRequestDto requestDto,
                                      HttpServletRequest httpServletRequest){
        //세션으로 로그인 상태 확인
        if(httpServletRequest.getSession(false) != null){
            throw new ResponseStatusException(HttpStatus.CONFLICT, "로그인 해주세요.");
        }
				//Service 에서 UserDto 반환
        LoginResponseDto loginResponseDto = userService.login(requestDto);
        //세션에 "userId" 라는 ID 값으로 정보 저장
        HttpSession session = httpServletRequest.getSession();
        session.setAttribute("userId", loginResponseDto.getId());
				//문자열 응답과 200(OK) 전달
        return new ResponseEntity<>("로그인 되었습니다.",HttpStatus.OK);
    }
}

6. Client

  • PostMan을 통해 데이터를 보내준다.
  • 요청 성공 시, 200 OK 메세지가 표시되고 세션에 로그인 상태가 저장된다.

요청 데이터 형식

URL 예시 : (POST)localhost:8080/users/signup

body 예시
{
    "email" : "myEmail@gogle.com",
    "password" : "password123!"
}

200 OK 와 로그인 성공 메시지

세션에 저장된 상태

7. 로그아웃

  • 먼저 세션을 확인해서 로그인 상태가 아니라면 예외처리 해준다.
  • 세션과 쿠키를 만료하는 메서드로 세션을 만료시킨다.
  • 보통은 invalidate() 만 사용해도 로그아웃 처리가 되지만, PostMan 에서는 자체적으로 쿠키를 계속 보내고 있기 때문에 쿠키도 즉시 만료시키는 로직을 실행시켜줘야 한다.
  • 세션 만료 후 메세지와 함께 200 OK 를 반환해준다.
@PostMapping("/logout")
public ResponseEntity<String> logout(HttpServletRequest request,
                                     HttpServletResponse response){
    //세션 확인 후 비 로그인 상태라면 예외처리                                 
    HttpSession session = request.getSession(false);
    if(session == null){
        throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "로그인 해주세요.");
    }
		//세션 및 쿠키 만료 메서드
    resetSessionAndCookies(session, response);

    return new ResponseEntity<>("로그아웃 되었습니다.",HttpStatus.OK);
}

//세션 및 쿠키 만료 메서드
private void resetSessionAndCookies(HttpSession session, HttpServletResponse response){
    //세션 만료
    session.invalidate();
    // postman 에서는 서버에서 자체적으로 쿠키(JSESSIONID)를 계속 보냄
    Cookie cookie = new Cookie("JSESSIONID", null);
    cookie.setPath("/");
    cookie.setMaxAge(0); // 즉시 만료
    response.addCookie(cookie);
}
profile
기어 올라가는 개발

0개의 댓글