BE/Spring

스프링 MVC 2 - 로그인 처리 세션 직접 구현

오봉봉이 2022. 8. 29. 00:58
728x90

로그인 처리 - 세션 직접 만들기

세션을 직접 개발해서 사용해보자.

세션 관리는 크게 3가지 기능을 제공하면 된다

  • 세션 생성
    • sessionId 생성(임의의 추정 불가능한 랜덤 값)
    • 세션 저장소에 sessionId와 보관할 값 저장
    • sessionId로 응답 쿠키를 생성해서 클라이언트에 전달
  • 세션 조회
    • 클라이언트가 요청한 sessionId 쿠키의 값으로 세션 저장소에 보관한 값 조회
  • 세션 만료
    • 클라이언트가 요청한 sessionId 쿠키의 값으로 세션 저장소에 보관한 sessionId와 값 제거

SessionManager - 세션 관리

@Component
public class SessionManager {

    private static final String SESSION_COOKIE_NAME = "mySessionId";
    private Map<String, Object> sessionStore = new ConcurrentHashMap<>();

    // 세션 생성
    public void createSession(Object value, HttpServletResponse response) {
        // 세션 id를 생성하고, 값을 세션에 저장
        String sessionId = UUID.randomUUID().toString();
        sessionStore.put(sessionId, value);
        Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
        response.addCookie(mySessionCookie);
    }

    // 세션 조회
    public Object getSession(HttpServletRequest request) {
//        Cookie[] cookies = request.getCookies();
//
//        for (Cookie cookie : cookies) {
//            if (cookie.getName().equals(SESSION_COOKIE_NAME)) {
//                return sessionStore.get(cookie.getValue());
//            }
//        }
        // 위 코드를 아래 코드로 변환 가능
        Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
        if (sessionCookie == null) {
            return null;
        }

        return sessionStore.get(sessionCookie.getValue());
    }

    // 세션 만료
    public void expire(HttpServletRequest request) {
        Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
        if (sessionCookie != null) {
            sessionStore.remove(sessionCookie.getValue());
        }
    }

    private Cookie findCookie(HttpServletRequest request, String cookieName) {
        if (request.getCookies() == null) {
            return null;
        }
        // request.getCookie()의 반환 값은 Array임
        return Arrays.stream(request.getCookies()) // Array를 Stream으로 바꿔준다.
                .filter(cookie -> cookie.getName().equals(cookieName)) // filter를 통해 파라미터 cookieName과 같은 것을 찾아냄
                .findAny() // 같은 것들 중 처음 검색되는 하나만 반환, 검색되는 것들 중에서 첫 번째에 있는 findFirst()를 사용해도 된다.
                .orElse(null); // 검색되는 것이 없으면 Null 반환
    }
}
  • @Component : 스프링 빈으로 자동 등록
  • ConcurrentHashMap : HashMap은 동시 요청에 안전하지 않기 때문에 동시요청에 안전한 ConcurrentHashMap 사용

SessionManagerTest - 테스트

class SessionManagerTest {

    SessionManager sessionManager = new SessionManager();

    @Test
    void sessionTest() {
        // 세션 생성
        // HttpServletResponse, HttpServletRequest는 인터페이스다.
        // 톰캣같은 WAS가 별도로 제공하기 때문에 스프링에서는 테스트을 위해 Mock 객체를 제공한다.
        MockHttpServletResponse response = new MockHttpServletResponse();
        Member member = new Member();
        sessionManager.createSession(member, response);

        // 요청에 응답 쿠키 저장
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setCookies(response.getCookies());

        // 세션 조회
        Object result = sessionManager.getSession(request);
        assertThat(result).isEqualTo(member);

        // 세션 만료
        sessionManager.expire(request);
        Object expired = sessionManager.getSession(request);
        assertThat(expired).isNull();
    }
}

HttpServletRequest, HttpservletResponse객체를 직접 사용할 수 없기 때문에 테스트에서 비슷한 역할을 해주는 가짜 MockHttpServletRequest, MockHttpServletResponse를 사용했다.

출처 : 인프런 김영한 지식공유자님 강의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
728x90