코알못

5분 안에 구축하는 로그인 서비스 - 쿠키&세션 본문

JAVA

5분 안에 구축하는 로그인 서비스 - 쿠키&세션

코린이s 2021. 7. 17. 16:13
728x90

쿠키 & 세션 (울랄라세션)   

로그인 서비스는 2가지 방식으로 구현이 가능하다

1. 쿠키&세션

2. JWT

해당 글에서는 1번 쿠키&세션을 이용한 방법으로 구성해본다!

위 두가지 방법에 대한 플로우는 아래 게시글에서 확인 가능하다

- 쿠키&세션 관련 플로우

 

[로그인] 로그인 유지는 어떻게 처리 하는 걸까?

인증 정보를 주고 받는 방식은 두가지 방법이 있다. 쿠키 & 세션 JWT 하나씩 알아보자! # 쿠키 & 세션 1. 로그인 2. 사용자 정보 요청 따라서 쿠키의 만료시간에 따라 로그인 유지가 된다. 쿠키의 만

co-de.tistory.com

일단 컨트롤러를 보자

/***
     * 로그인 페이지
     * @param request
     * @param model
     * @return
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String main(HttpServletRequest request, Model model){

        // 쿠키 만료시 Cookie 값이 null이 된다. (유효 시간 동안은 개발자 모드 진입 후(F12) 쿠키 보면 AUTH 라는 이름으로 세션 ID가 들어가 있음)
        Cookie auth = WebUtils.getCookie(request, "AUTH");

        // 로그인 정보가 있을시
        if(!ObjectUtils.isEmpty(auth)){
            if(StringUtils.equalsIgnoreCase(auth.getValue(), request.getSession().getId())){
                String username = (String) request.getSession().getAttribute("username");
                if(StringUtils.isNotEmpty(username)){
                    model.addAttribute("username", username);
                    return "success";
                }
            }
        }
        // 로그인 만료 or 비 로그인자 일시
        return "login";
    }

    /***
     * 로그인 요청
     * @param member
     * @param request
     * @param response
     * @param model
     * @return
     */
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public String login(Member member, HttpServletRequest request, HttpServletResponse response, Model model){

        // 세션 저장 (세션 ID, 사용자 정보)
        // 세션은 브라우저 당 1개 생성(시크릿 모드도 동일, 같은 브라우저에서 새탭 or 새창 띄워도 로그인 유지) / 쿠키는 시크릿 모드시 없어짐
        request.getSession().setAttribute("username", member.getUsername());

        // 쿠키 전달 (세션 ID)
        response.addCookie(new Cookie("AUTH", request.getSession().getId()){{
            setMaxAge(60); // 자동 로그인 10 초 유지
            setPath("/");
        }});

        // 화면에 표시할 ID 셋팅
        model.addAttribute("username", member.getUsername());
        return "success";
    }

    /***
     * 로그아웃 요청
     * @param request
     * @return
     */
    @RequestMapping(value = "/logout")
    public String logout(HttpServletRequest request){
        // 세션 저장소 세션 제거
        request.getSession().invalidate();
        return "redirect:/";
    }

로그인 '/' GET 은 초기 로그인 진입 화면이며, 아래 세가지를 확인하여 정상 로그인 여부를 확인 한다.

1. 저장한 쿠키인 AUTH 가 있는가?

2. 현재 세션값과 쿠키에 저장된 세션값 비교시 같은가?

3. 해당 세션에 저장된 사용자 정보(username)가 있는가?

정상 로그인 이라면 로그인 완료 화면인 success.html 로 넘기고 아니라고 하면 로그인 페이지인 login.html 로 넘긴다.

 

로그인 '/' POST는 로그인 요청이며, 아래 3가지 작업후 로그인 완료 화면으로 넘긴다.

1. 세션에 사용자 정보(username)를 저장한다. (저장소 : 서버)

2. 세션 ID 를 쿠키에 저장한다. (저장소 : 클라이언트=브라우저)

- maxage 는 쿠키 유지 시간으로 현재 60초 동안 쿠키가 유지되도록 설정하여 60초 동안은 로그인이 유지 된다.

- path 는 '/' 아래 경로에서 쿠키값을 유지한다는 의미 

3. 사용자 정보(username)을 로그인 완료 화면에 보여주기 위해 해당 값을 model로 넘겨준다.

 

로그아웃 API '/logout' 는 해당 세션을 무효화 시킨다.

 

로그인 화면은 부트스트랩을 사용하여 나름 이쁘게(?) 구성한다.

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

로그인 폼은 아래와 같이 ID/PW를 받는다

<form action="/" method="post">
                <div class="mb-3">
                    <label for="username" class="form-label">ID</label>
                    <input type="text" class="form-control" id="username" name="username">
                </div>
                <div class="mb-3">
                    <label for="password" class="form-label">Password</label>
                    <input type="password" class="form-control" id="password" name="password">
                </div>
                <button type="submit" class="btn btn-primary" id="loginBtn">Submit</button>
 </form>

로그인 완료 화면은 세션에서 얻은 username 정보를 모델에 넣어 뿌린다

<div class="col-6 col-md-4">
            <p th:text="${username}+'님 로그인 완료 !!!'"></p>
            <form action="/logout">
                <button type="submit" class="btn btn-primary" id="logoutBtn">LogOut</button>
            </form>
</div>

 

완성 코드는 아래 깃에서 다운 받아보면 된다!

:: https://github.com/works-code/login-cookie-session

 

works-code/login-cookie-session

로그인 세션&쿠키 스타터 코드. Contribute to works-code/login-cookie-session development by creating an account on GitHub.

github.com

테스트를 해본다 !

http://localhost:8080/ 으로 로그인 페이지를 호출한다

hello 라는 ID로 로그인을 한다!

새탭을 켜서 로그인 페이지를 접근하여 로그인 유지가 되는지 확인 한다. (새탭을 켜도 같은 세션 아이디임을 확인 할 수 있다.)

새창을 켜도 로그인 유지가 될까? (새창을 켜도 같은 세션 아이디임을 확인 할 수 있다.)

 

다른 브라우저로 접속해볼까?(브라우저 당 1개의 세션이 생성되는것을 확인 할 수 있다.)

브라우저 별로 세션 ID가 달라서 다른 ID 로 로그인 유지 가능하다

 

로그인 후에 새창을 띄워 시크릿창을 켜보면 로그인이 풀려있는 것을 확인 할 수 있다.

- 로그 확인 해보면 세션 아이디를 새로 발급하는것을 확인 할 수 있다.

// 일반
2021-07-17 17:19:12.055 ERROR 34600 --- [nio-8080-exec-7] com.code.controller.LoginController      : ### session ID => CF239613C901300405757CDCBFE7EC78
// 시크릿 창
2021-07-17 17:19:27.782 ERROR 34600 --- [nio-8080-exec-9] com.code.controller.LoginController      : ### session ID => FF20C1742220BA8314E0A55CAC8939B8

로그아웃을 해볼까? 메인으로 돌아오면서 세션 ID가 새로 생성 된다.

 

- request.getSession() 시점에 유효한 세션이 있으면 해당 세션을 반환하고 없으면 새로 생성한다.

- 로그를 찍어보면 로그아웃(request.getSession().invalidate();) 을 하고 나서 세션 아이디를 보면 새로 생성된것을 확인 할 수 있다.

// 로그인 후 세션 아이디
2021-07-17 16:47:31.472 ERROR 33637 --- [nio-8080-exec-4] com.code.controller.LoginController      : ### session ID => D81F996D7A7C2536E860DC473CF4004A
// 로그아웃 후 세션 아이디
2021-07-17 16:47:31.476 ERROR 33637 --- [nio-8080-exec-5] com.code.controller.LoginController      : ### session ID => 2909BC4ED82A0FF91C110D309F9809B9

 

로그인 후 60초를 기다리면 로그인이 풀리는지 확인 한다.

- 개발자 모드(F12) 접속하여 쿠키 확인해보면 AUTH가 정상적으로 만료 시간 (60초)로 들어간것을 확인 할 수 있으며

- 60초 뒤에 확인해보면 AUTH 쿠키가 사라진 것을 볼 수 있다.

- 이때 로그아웃을 한게 아니라서 세션 ID는 같다! (쿠키만 지워진것)

2021-07-17 16:58:30.913 ERROR 33637 --- [nio-8080-exec-8] com.code.controller.LoginController      : ### session ID => A51446D33A7F440F4A2E9148EDBCCA15
2021-07-17 17:00:05.595 ERROR 33637 --- [nio-8080-exec-1] com.code.controller.LoginController      : ### session ID => A51446D33A7F440F4A2E9148EDBCCA15

- 쿠키 만료후 재 로그인시에 사용자 정보를 해당 세션에 넣을시 같은 키값에 데이터가 있다면 새로운 값으로 교체 된다. 

request.getSession().setAttribute("username", member.getUsername());

 

정리하면 아래와 같다!

- 세션 ID 는 브라우저 별로 1개씩 생성하며, 시크릿 모드 접속시 쿠키 제거 되며 세션 ID를 새로 발급한다. (새창, 새탭 같은 세션 ID 사용)

- 로그아웃 시 세션 무효화 하면 (request.getSession().invalidate();) 세션 ID를 사용할 수 없게 되어 세션 ID를 새로 발급 한다.

- 쿠키 만료시 자동으로 로그인이 풀리며 이때 쿠키만 만료되어 사라진것이므로 세션 ID 는 동일하다. (이때 세션 ID 에 저장된 사용자 정보는 재 로그인시 overwrite 된다.) 

 

다음 포스팅에서는 JWT 방식으로 구현 해볼 예정이다!

- 끝-

728x90
Comments