본문 바로가기
개념서/Spring

[Spring] Session 기반 로그인 구현하기

by 사서T 2023. 2. 5.

Session 등록 과정

1. 서버에 요청

2. Session ID 생성 및 저장

3. 생성된 Session ID 반환

4. Session Id 쿠키 저장

 

Session 인증 과정

1. Session ID가 저장된 쿠키 전송

2. 전달된 Session ID 유효성 판단

    2-1. 유효한 경우 이후 작업 진행

    2-2. 유효하지 않은 경우 Session 만료 메시지 or Redirect 진행

 

로그인 구현하기

방법1. @SessionAttribute

로그인 상태를 표현하기위한 html이 필요하다. home.html은 로그인이 안된 상태, home2.html은 로그인이 된 상태를 나타낸다. 로그인 버튼 클릭시 로그인 정보를 입력하는 form 페이지로 이동하며, 로그아웃 버튼 클릭시 서버에 저장된 세션 제거 후 home.html로 리다이렉션한다.

 

<home.html>

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
    <form th:action="@{/session/form}" method="get">
      <button type="submit">로그인</button>
    </form>
</body>
</html>

 

<home2.html>

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
    <p th:text="${memberId}"/>
    <form th:action="@{/session/logout}" method="post">
        <button type="submit">로그아웃</button>
    </form>
</body>
</html>

 

다음은 로그인 정보를 넘길 form.html을 구현하자.

 

<form.html>

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<form th:action="@{/session/login}" method="post">
  <input type="text" name="memberId">
  <input type="text" name="password">
  <button type="submit">등록</button>
</form>
</body>
</html>

 

이제 요청을 처리할 컨트롤러가 필요하다. form.html을 반환해줄 메서드와 login을 처리할 메서드를 구현해주자. form() 메서드는 단순히 templates에서 form.html을 찾아 반환하는 역할을 한다. login() 메서드는 <form> 태그로 전송한 memberId, password와 request를 파라미터로 받는다. 이후 getSession() 메서드로 요청과 관련된 세션을 호출(없는 경우 생성)하고 setAttribute() 메서드로 세션에 저장할 데이터와 데이터명을 설정한다. 로그인된 상태를 확인하기위해 home으로 리다이렉션을 진행한다.

만약 로그인시 memeberId나 password 검증 과정에서 실패하게 되면 에러 메시지 출력이나 리다이렉션 등의 처리를 수행해야 한다. (여기선 언제나 존재하는 정보만 들어온다는 가정하에 진행한다.)

 

@Controller
@RequestMapping("session")
public class SessionTestController {

    @GetMapping("/form")
    public String form() {
        return "form";
    }

    @PostMapping("/login")
    public String login(@RequestParam String memberId, @RequestParam String password,
                                HttpServletRequest request) {
        //memberId와 password 검증 로직 생략
        HttpSession session = request.getSession();
        session.setAttribute("memberInfo", memberId);
        return "redirect:/test/home";
    }
}

 

로그인 상태를 확인하기위해 컨트롤러에 home() 메서드를 추가해보자. @SessionAttribute는 메서드 파라미터에 세션 속성을 바인딩하기 위한 애너테이션이다. name은 세션 저장소에 저장된 데이터명, required는 세션 속성이 필수적인지를 설정한다. 따라서 다음에 선언된 @SessionAttribute는 세션 저장소에 저장된 데이터명이 "memberInfo"에 대해 유효성 검증을 진행하지만 memberId가 없어도 상관없음을 의미한다. memberInfo가 없는 경우 memberId는 null로 초기화된다. (required를 false로 설정한 이유는 home메서드는 로그인이 안된 상태여도 접근이 가능하기 때문이다.)

@SessionAttribute가 선언된 파라미터의 상태에 따라 로그인 상태를 알 수 있다. memberId가 null인 경우 로그인이 안된 상태이기 때문에 home.html을 반환, memberId가 유효한 경우 home2.html을 반환한다.

 

@GetMapping("/home")
public String home(@SessionAttribute(name = "memberInfo", required = false) String memberId, Model model) {
    if (value == null)
        return "home";
    model.addAttribute("memberId", memberId);
    return "home2";
}

 

로그인을 구현했으니 이제 로그아웃을 구현해보자. 로그아웃에도 @SessionAttribute를 이용해 memberId를 바인딩한다. memberId가 존재하는 경우 removeAttributes() 메서드를 이용해 세션 저장소에 "memberInfo"를 key로 갖는 데이터를 삭제한다. (삭제하지 않으면 메모리 낭비 발생) 세션 처리후 home() 메서드를 호출해 home.html로 리다이렉션 시킨다.

 

@PostMapping("/logout")
public String logout(@SessionAttribute(name = "memberInfo", required = false) String memberId,
                     HttpServletRequest request) {
    if (value != null) {
        request.getSession().removeAttribute("memberInfo");
    }
    return "redirect:/test/home";
}

 

@SessionAttribute의 required 옵션을 false로 설정한 이유가 궁금할 수 있다. 로그아웃 버튼은 로그인한 상태에서만 노출되기 때문에 그렇게 생각할 수 있지만 사용자가 장시간 자리를 비워 세션이 만료된 경우를 고려해야 한다. 그렇다면 세션을 시간 제한없이 사용 가능하게 설정하면 좋지 않을까? 세션 ID가 탈취 당하면 사용자의 정보가 노출될 수 있기 때문에 세션을 무제한 사용 가능하게 설정하는 것은 위험성이 크다. 또 사용자가 로그아웃 하지않고 브라우저를 종료하는 경우도 고려해 세션에 유효시간을 설정해야 한다.

 

세션 시간 설정의 중요성을 이해했으니 application.properties에 다음과 같이 timeout을 설정하자.

 

server.servlet.session.timeout=1800 //기본 초단위, 최소 30분, 10s(10초), 30m(30분)

 

테스트 도중 url에 jsessionid=9BBFC90B4A16F157B1131AA771D1DF36이 붙는 상황을 마주할 수 있다. 이는 클라이언트가 쿠키를 지원하는지 알 수 없기 때문에 생성된 세션 ID를 url과 쿠키에 모두 넣어주게되어 발생하는 현상이다. sessionid가 노출되면 안정성 이슈가 있기 때문에 application.properties에 다음을 추가하자.

 

server.servlet.session.tracking-modes=cookie

 

JWT 기반 로그인 구현하기

 

참고자료

스프링 로그인 처리

Session 로그인 기능

Session Timeout 설정

url에 jsessionid가?

'개념서 > Spring' 카테고리의 다른 글

[Spring] 이메일 전송 구현하기  (0) 2023.02.13
[Spring] JWT 기반 로그인 구현하기  (0) 2023.02.06
[Spring] @ControllerAdvice, @RestControllerAdvice  (0) 2023.02.01
[Spring] @ExceptionHandler  (0) 2023.01.31
[Spring] 예외처리  (0) 2023.01.31

댓글