컴퓨터 프로그래밍/Spring

[Spring] 인증과 인가, 쿠키와 세션

한33 2024. 8. 24. 14:43

인증과 인가

  • 인증(Authentication)
    • 인증은 해당 유저가 실제 유저인지 인증하는 개념
    • 스마트폰에 지문인식, 이용하는 사이트에 로그인 등과 같이, 실제 그 유저가 맞는지를 확인하는 절차
  • 인가(Authorization)
    • 인가는 해당 유저가 특정 리소스에 접근이 가능한지 허가를 확인하는 개념
    • 예를들어 관리자 페이지-관리자 권한

인증의 방식

  • 쿠키-세션 방식은 서버가 ‘특정 유저가 로그인 되었다’는 상태를 저장하는 방식.
  • 인증과 관련된 아주 약간의 정보만 서버가 가지고 있게 되고 유저의 이전 상태의 전부는 아니더라도 인증과 관련된 최소한의 정보는 저장해서 로그인을 유지시킨다는 개념.

 

  1. 사용자가 로그인 요청을 보냅니다.
  2. 서버는 DB의 유저 테이블을 뒤져서 아이디 비밀번호를 대조해봐야겠죠?
  3. 실제 유저테이블의 정보와 일치한다면 인증을 통과한 것으로 보고 “세션 저장소”에 해당 유저가 로그인 되었다는 정보를 넣습니다.
  4. 세션 저장소에서는 유저의 정보와는 관련 없는 난수인 session-id를 발급합니다.
  5. 서버는 로그인 요청의 응답으로 session-id를 내어줍니다.
  6. 클라이언트는 그 session-id를 쿠키라는 저장소에 보관하고 앞으로의 요청마다 세션아이디를 같이 보냅니다. (주로 HTTP header에 담아서 보냅니다!)
  7. 클라이언트의 요청에서 쿠키를 발견했다면 서버는 세션 저장소에서 쿠키를 검증합니다.
  8. 만약 유저정보를 받아왔다면 이 사용자는 로그인이 되어있는 사용자겠죠?
  9. 이후에는 로그인 된 유저에 따른 응답을 내어줍니다.

  • JWT(JSON Web Token)란 인증에 필요한 정보들을 암호화시킨 토큰을 의미.
  • JWT 기반 인증은 쿠키/세션 방식과 유사하게 JWT 토큰(Access Token)을 HTTP 헤더에 실어 서버가 클라이언트를 식별
  1. 사용자가 로그인 요청을 보냅니다.
  2. 서버는 DB의 유저 테이블을 뒤져서 아이디 비밀번호를 대조해봐야겠죠?
  3. 실제 유저테이블의 정보와 일치한다면 인증을 통과한 것으로 보고 유저의 정보를 JWT로 암호화 해서 내보냅니다.
  4. 서버는 로그인 요청의 응답으로 jwt 토큰을 내어줍니다.
  5. 클라이언트는 그 토큰을 저장소에 보관하고 앞으로의 요청마다 토큰을 같이 보냅니다.
  6. 클라이언트의 요청에서 토큰을 발견했다면 서버는 토큰을 검증합니다.
  7. 이후에는 로그인 된 유저에 따른 응답을 내어줍니다.

쿠키와 세션

쿠키와 세션 모두 HTTP 에 상태 정보를 유지(Stateful)하기 위해 사용됨.

즉, 쿠키와 세션을 통해 서버에서는 클라이언트 별로 인증 및 인가를 할 수 있게 된다.

 

1. 쿠키

클라이언트에 저장될 목적으로 생성한 작은 정보를 담은 파일

  • 구성요소
    • Name (이름): 쿠키를 구별하는 데 사용되는 키 (중복될 수 없음)
    • Value (값): 쿠키의 값
    • Domain (도메인): 쿠키가 저장된 도메인
    • Path (경로): 쿠키가 사용되는 경로
    • Expires (만료기한): 쿠키의 만료기한 (만료기한 지나면 삭제됩니다.)

2. 세션

  • 서버에서 일정시간 동안 클라이언트 상태를 유지하기 위해 사용
  • 서버에서 클라이언트 별로 유일무이한 '세션 ID' 를 부여한 후 클라이언트 별 필요한 정보를 서버에 저장
  • 서버에서 생성한 '세션 ID' 는 클라이언트의 쿠키값('세션 쿠키' 라고 부름)으로 저장되어 클라이언트 식별에 사용됨
  • 세션 동작 방식

위 그림에서와 같이 서버는 세션ID 를 사용하여 세션을 유지함

  1. 클라이언트가 서버에 1번 요청
  2. 서버가 세션ID 를 생성하고, 쿠키에 담아 응답 헤더에 전달
    1. 세션 ID 형태: "SESSIONID = 12A345"
  3. 클라이언트가 쿠키에 세션ID를 저장 ('세션쿠키')
  4. 클라이언트가 서버에 2번 요청
    • 쿠키값 (세션 ID) 포함하여 요청
  5. 서버가 세션ID 를 확인하고, 1번 요청과 같은 클라이언트임을 인지


쿠키 생성

public static void addCookie(String cookieValue, HttpServletResponse res) {
    try {
        cookieValue = URLEncoder.encode(cookieValue, "utf-8").replaceAll("\\+", "%20"); // Cookie Value 에는 공백이 불가능해서 encoding 진행

        Cookie cookie = new Cookie(AUTHORIZATION_HEADER, cookieValue); // Name-Value
        cookie.setPath("/");
        cookie.setMaxAge(30 * 60);

        // Response 객체에 Cookie 추가
        res.addCookie(cookie);
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e.getMessage());
    }
}
  • new Cookie(AUTHORIZATION_HEADER, cookieValue);
    • Cookie에 저장될 Name과 Value를 생성자로 받는 Cookie 객체를 생성
  • setPath("/"), setMaxAge(30 * 60)
    • Path와 만료시간을 지정
  • HttpServletResponse 객체에 생성한 Cookie 객체를 추가하여 브라우저로 반환
    • 이렇게 반환된 Cookie는 브라우저의 Cookie 저장소에 저장됨
  • Cookie 생성은 범용적으로 사용될 수 있기 때문에 static 메서드로 선언

쿠키 읽기

@GetMapping("/get-cookie")
public String getCookie(@CookieValue(AUTHORIZATION_HEADER) String value) {
    System.out.println("value = " + value);

    return "getCookie : " + value;
}
  • @CookieValue("Cookie의 Name")
    • Cookie의 Name 정보를 전달해주면 해당 정보를 토대로 Cookie의 Value를 가져옴

세션 다루기

Servlet에서는 유일무이한 '세션 ID'를 간편하게 만들수 있는 HttpSession을 제공 해줌

 

HttpSession 생성

@GetMapping("/create-session")
public String createSession(HttpServletRequest req) {
    // 세션이 존재할 경우 세션 반환, 없을 경우 새로운 세션을 생성한 후 반환
    HttpSession session = req.getSession(true);

    // 세션에 저장될 정보 Name - Value 를 추가합니다.
    session.setAttribute(AUTHORIZATION_HEADER, "Robbie Auth");

    return "createSession";
}
  • HttpServletRequest를 사용하여 세션을 생성 및 반환할 수 있음
  • req.getSession(true)
    • 세션이 존재할 경우 세션을 반환하고 없을 경우 새로운 세션을 생성
  • 세션에 저장할 정보를 Name-Value 형식으로 추가함
  • 반환된 세션은 브라우저 Cookie 저장소에 ‘JSESSIONID’라는 Name으로 Value에 저장됨

HttpSession 읽기

@GetMapping("/get-session")
public String getSession(HttpServletRequest req) {
    // 세션이 존재할 경우 세션 반환, 없을 경우 null 반환
    HttpSession session = req.getSession(false);

    String value = (String) session.getAttribute(AUTHORIZATION_HEADER); // 가져온 세션에 저장된 Value 를 Name 을 사용하여 가져옵니다.
    System.out.println("value = " + value);

    return "getSession : " + value;
}
  • req.getSession(false)
    • 세션이 존재할 경우 세션을 반환하고 없을 경우 null을 반환
  • session.getAttribute(”세션에 저장된 정보 Name”)
    • Name을 사용하여 세션에 저장된 Value를 가져옴