로그인 처리 방식 - 세션 v3

Yangray·2021년 9월 16일
1

Spring 로그인 구현

목록 보기
4/4

🐱‍🚀지난 포스팅에서 서블릿이 제공하는 HttpSession이라는 기능으로 로그인 구현을 공부했다.
이번에는 스프링은 어떻게 세션을 편리하게 사용할 수 있는지에 공부해볼 예정이다.

@SessionAttribute

  • 스프링은 세션을 더 편리하게 사용할 수 있도록 @SessionAttribute을 지원한다.
  • 이미 로그인 된 사용자를 찾을 때는 다음과 같이 사용하면 된다. 참고로 이 기능은 세션을 생성하지 않는다.
    @SessionAttribute(name = "loginMember", required = false) Member loginMember
@SessionAttribute에서 지정한 이름 'loginMember'와 동일한 이름이 존재하면 이를 세션에 저장해준다.

``` java
  @GetMapping("/")
    public String homeLoginV3Spring(
            @SessionAttribute(name = SessionConst.LOGIN_MEMBER,required = false) Member loginmember,
            Model model) {
            //세션에 회원 데이터가 없으면 home
        if(loginmember == null){
            return "home";
        }
         //세션이 유지되면 로그인으로 이동
        model.addAttribute("member",loginmember);
        return "loginHome";
    }

세션을 찾고, 세션에 들어있는 데이터를 찾는 번거로운 과정을 스프링이 한번에 편리하게 처리해주는 것을
확인할 수 있다

TrackingModes

로그인을 처음 시도하면 URL이 다음과 같이 jessionid를 포함하고 있는 것을 확인할 수 있다.
http://localhost:8080/;jsessionid=F59911518B921DF62D09F0DF8F83F872
이것은 웹 브라우저가 쿠키를 지원하지 않을 때 쿠키 대신 URL을 통해서 유지하는 방법이다.
이 방법을 사용하려면 URL에 이 값을 계속 포함해서 전달해야 한다.
서버 입장에서 웹 브라우저가 쿠키를 지원하는지 하지 않는지 최초에는 판단하지 못하므로, 쿠키 값도 전달하고, URL에 jsessionid도 함께 전달한다.
URL 전달 방식을 끄고 항상 쿠키를 통해서만 세션을 유지하고 싶으면 다음 옵션을 넣어주면 된다.
application.properties나 application.yaml
server.servlet.session.tracking-modes=cookie를 추가하면 된다.

세션 정보와 타임아웃 설정

세션이 제공하는 정보들을 확인해보자.

@Slf4j
@RestController
public class SessionInfoController {

    @GetMapping("/session-info")
    public String sessionInfo(HttpServletRequest request){
        HttpSession session = request.getSession(false);
        if(session == null){
            return "세션이 없습니다.";
        }
        session.getAttributeNames().asIterator()
                .forEachRemaining(name -> log.info("session name={},value={}", name, session.getAttribute(name)));

        log.info("sessionId={}",session.getId());
        log.info("getMaxInactiveInterval={}",session.getMaxInactiveInterval());
        log.info("creationTime={}", new Date(session.getCreationTime()));
        log.info("lastAccessedTime={}", new Date(session.getLastAccessedTime()));
        log.info("isNew={}", session.isNew());

        return "세션 출력";
    }
}

sessionId : 세션id, JSESSIONID의 값이다.
maxInactiveInterval : 세션의 유효 시간 예) 1800초 = 30분
creationTime : 세션 생성일지
lastAccessedTime : 세션과 연결된 사용자가 최근에 서버에 접근한 시간, 클라이언트에서 서버로 sessionId를 요청한 경우에 갱신된다.
isNew : 새로 생성된 세션인지, 아니면 이미 만들어졌고, 클라이언트에서 서버로 sessionId를 요청해서 조회된 세션인지 여부

세션 타임아웃 설정

세션은 사용자가 로그아웃을 직접 호출해 session.invalidate()가 호출 되는 경우에 삭제된다.
하지만 로그아웃을 하지 않고, 웹 브라우저를 종료하면 HTTP는 비연결성이기 때문에 서버는 웹 브라우저를 종료한 것인지 아닌지 인식을 할 수 없다. 서버는 세션데이터를 언제 삭제해야 하는지 판단하기 어려워져 남아있는 세션을 무한정 보관하게 되어 여러 문제가 발생 가능해진다.

예를들면, 세션과 관련된 쿠키를 탈취 당했을 경우 오랜 시간이 지나도 해당 쿠키로 악의적인 요청을 할 수 있게된다.
그리고 세션은 기본적으로 메모리에 생성이 되는데 메모리의 크기는 무한하지 않기 때문에 공간의 비효율성이 발생하게 되는 문제가 생긴다.

🤔 그렇다면 세션의 종료 시점을 어떻게 정하면 좋을까???

세션은 사용자가 서버에 최근에 요청한 시간을 기준으로 30분 정도를 유지해주는 방법이 있다.
세션을 생성 시점으로 30분 유지해주는 방법도 있는데, 이 방법은 사용자가 사이트를 돌아 다니면서 서버에 요청을 계속하고 있는데 30분이 지나면 다시 로그인을 해서 세션을 생성해야 하므로 30분마다 로그인을 해야하는 번거로움이 발생하기 때문에 위 방법이 사용자에게 번거로움없이 세션을 유지하고 자동적으로 종료되게 하는 방법이다.서블릿에서 제공하는 HttpSession은 이 방식을 사용한다.

스프링 부트로 글로벌 설정

application.properties나 yaml에
server.servlet.session.timeout=60 설정하여 글로벌 설정할 수 있으며, 글로벌 설정은 분 단위로 설정해야 한다.

특정 세션 단위로 시간 설정

session.setMaxInactiveInterval(1800); //1800초
하여 특정 세션 단위로도 설정이 가능하다.

세션의 타임아웃 시간은 해당 세션과 관련된 JSESSIONID를 전달하는 HTTP 요청이 있으면 현재 시간으로 다시 초기화 된다.

session.getLastAccessedTime() : 최근 세션 접근 시간

LastAccessedTime이후로 타임아웃 시간이 지나면 WAS가 내부에서 해당 세션을 제거한다.

정리

서블릿에서 HttpSession을 제공하는데 이를 스프링에서 더 편리하게 사용하도록 해주는 @SessionAttribute에 대해 공부해보고, 부가적인 내용들도 공부해보았다.
이 기능은 세션을 찾고, 세션에 들어있는 데이터를 찾는 번거로운 과정을 스프링이 한번에 편리하게 처리해주는 것을 확인할 수 었다.
그리고 세션은 타임아웃 설정을 통해 불필요한 데이터들을 유지하는 문제와 탈취 되었을 경우 발생되는 문제 등 여러문제들을 해결할 수 있게 되었다.

profile
시작은 미약하나 그 끝은 창대하리라

0개의 댓글