
인증과 인가의 차이가 무엇일까?
- 간단하게 설명하자면
- 인증 = 아이디, 비밀번호를 입력하고 제출하여 유저인지 확인하는 절차! (지문인식 같이)
- 인가 = 회원/비회원의 여부에 맞게 특정 리소스에 대한 접근 권한을 주는 것!(관리자 권한처럼)
그렇다면, 웹 애플리케이션 인증은 다를까?
- 서버 - 클라이언트 구조로 되어있는 웹은 Http라는 프로토콜을 이용하여 통신합니다
- 그리고 이 통신은 "비연결성(Connectionless), 무상태(Stateless)"로 이루어지는데
- 비연결성(Connectionless)
- 서버- 클라이언트가 연결되어 있지 않다는 의미!
- 왜 연결을 안하나요?
- 계속 연결을 해놓으면 서버의 비용이 너무 많이 들기때문!
- 즉, 서버는 하나의 요청 - 하나의 응답 - 연결 종료를 하고 있습니다
- 무상태( Stateless)
- 서버가 클라이언트의 상태를 저장하지 않는다는 의미!
- 왜 저장을 안하나요?
- 수 많은 클라이언트들의 정보를 저장하기엔 비용이 너무 많이 들기 때문!
- 그러므로 서버는 이전에 클라이언트가 어떤 요청을 보냈는지 알 수가 없다
- 비연결성(Connectionless)

하지만, 클라이언트가 인터넷을 사용할 때 연속성이 있는 것처럼 사용했는데..?
- 그 이유는 클라이언트들이 그렇게 느끼도록 하기위해 url를 계층적으로 설계하기 때문!
- 바로 /News/Issue/8 처럼 다음 요청에 대한 api url를 이전 계층에 두면 연속적이라 느낍니다
그럼 해당 클라이언트가 인증되었다는 정보를 어떻게 유지할까?
- 웹 어플리케이션은 인증을 처리하는 방법이 2가지가 있다.
1. 쿠키 - 세션 방식의 인증
- 쿠키: 저장 공간 / 세션: 인증 정보(ID/식별자 값같은) = HTTP에 상태정보 유지를 위해 사용
- 특정 유저가 로그인이 되었다라는 상태를 저장하는 방식
- 인증과 관련된 최소한의 정보를 저장하여 유지시키는 느낌!
- JWT와 다른 점은 세션 저장소가 있다는 것
- 흐름을 보면
- 로그인을 하면 DB에서 회원인지 확인을 하고(인증)
- 세션 저장소에 회원정보를 저장하고
- 세션) 유저 정보와 관련이 없는 세션ID(난수)를 만들어 서버에게 전달 = 보안을 위해 생성
- 서버) 발급한 세션ID를 전달
- 클라이언트는 세션ID를 쿠키에 저장해 놓았다가 - 데이터 요청시 쿠키(세션ID)를 함께 전달(HTTP Header에)
- 서버) 쿠키가 있다면 세션저장소에 있는 정보랑 비교하여
- 클라이언트에게 요구에 맞는 응답 (예, 마이페이지의 포인트 정보)

2. JWT (JSON Web Token) 기반 인증
- JWT = 인증에 필요한 정보를 암호화한 토큰 (JSON형식으로 생긴 웹에서 사용하는 토큰)
- 쿠키/세션 방식과 유사한 느낌
- JWT 토큰을 HTTP Header에 담아 서버에서 클라이언트를 식별
- 흐름을 보면
- 로그인을 하면 회원 DB에서 비교하여 회원인지 확인하고(인증)
- 인증 통과하면 유저에 대한 정보를 JWT로 암호화
- JWT를 응답에 담아 클라이언트에게 전달
- 클라이언트는 쿠키저장소/로컬 스토리지에 JWT를 저장했다가
- 서버에 데이터 요청시에 JWT를 담아 함께 보내고
- 서버) 쿠키(JWT)가 있다면 검증 후 클라이언트에게 응답
- 세션 저장소를 쓰는 쿠키/세션 방식보다 서버에 부담이 적어 훨씬 더 효율적!

그렇다면 쿠키와 세션이 무엇인지 알아보자
- 쿠키와 세션은 모두 HTTP에 상태 정보를 유지하는데 사용됩니다 (서버에서 클라이언트 별 인증, 인가에 사용)
! 쿠키
- 클라이언트에 저장될 목적으로 생성한 정보를 담은 파일
- 저장 위치 : 클라이언트(웹 브라우저) = 웹 브라우저에서 개발자 도구에서 쿠키 확인 가능!
- 용량 : 브라우저 별로 상이 (크롬기준 도메인하나당 180개, 쿠키하나 4KB)
- name : 쿠키를 구별하는 키(pk) / value : 값
- domain : 저장된 도메인
- path : 쿠키 사용 경로
- Expires : 쿠키 만료 기한(기한이 지나면 쿠키는 삭제됨!) = 브라우저 종료시에도 유지 가능
- 보안에 취약하다는 단점! (클라이언트에서 정보 변경, 삭제 등이 쉽게 가능)

! 세션

- 서버에서 일정시간 동안 클라이언트의 상태를 유지하기 위해 사용!
- 저장 위치 : 웹 서버
- 만료 시점 (하나만 만족해도 만료)
- 브라우저 종료시
- 클라이언트 로그아웃시
- 서버에 설정한 유지기간까지 해단 클라이언트가 재요청하지 않는 경우
- 용량 : 세션 저장소 크기까지 (개수 제한x)
- 보안에 안전! = 서버에 저장되기 때문에 쿠키보다 안전
- 서버에서 만든 세션ID는 클라이언트의 쿠키(세션 쿠키)로 저장되어 클라이언트 식별에 사용
- 쿠키 - 세션 방식의 인증 흐름처럼 같은 클라이언트(브라우저)이구나를 인지하고 연속성이 있는 것처럼 느끼도록 만들어줍니다.
쿠키와 세션을 Spring에서 만들고 사용해볼까?
- 브라우저와 Spring이 쿠키를 주고 받는 걸 확인해보자
1. 먼저, 쿠키를 생성하는 메서드를 이해해보자
public static final String AUTHORIZATION_HEADER = "Authorization";
//name을 상수로 만들었습니다.
@GetMapping("/create-cookie")
public String createCookie(HttpServletResponse res) {
addCookie("Robbie Auth", res);
//쿠키의 value값에 공백이 있어요
return "createCookie";
}
public static void addCookie(String cookieValue, HttpServletResponse res) {
//HttpServletResponse res : selvet에서 만들어준 response객체에 데이터를 담으면 클라이언트에 자동으로 반환
try {
cookieValue = URLEncoder.encode(cookieValue, "utf-8").replaceAll("\\+", "%20");
// Cookie Value 에는 공백이 불가능해서 encoding 진행!
//.replaceAll("\\+", "%20"); 전체 공백을 변경
Cookie cookie = new Cookie(AUTHORIZATION_HEADER, cookieValue);
//cookie 생성자를 이용하여 담기
// Name-Value 모양으로 담고
//(메인부분에 Authorizaion이라는 이름으로 보내겠습니다)
cookie.setPath("/"); //set메서드를 이용하여 path넣고
cookie.setMaxAge(30 * 60); //만료기한 넣기
// Response 객체에 Cookie 추가 (이미 쿠키를 담을 공간이 존재해서 넣기만 하면 됩니다)
res.addCookie(cookie);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage());
}
}


2. 쿠키를 읽는 메서드는?
public static final String AUTHORIZATION_HEADER = "Authorization";
//쿠키 읽기(가져오기) = @CookieValue
@GetMapping("/get-cookie")
public String getCookie(@CookieValue(AUTHORIZATION_HEADER) String value) {
//@CookieValue(가져오는 값)을 넣어주면 가져오기 가능
//HttpServletRequest안에 들어있는 쿠키 중에서 AUTHORIZATION_HEADER라는 쿠키를 가져와 value에 담겠어요
System.out.println("value = " + value);
//value = Authorization
return "getCookie : " + value;
}


3. 세션을 만들어보자 (HttpSession 생성)
- Servlet에서는 유일무이한 세션ID를 간편하게 만들 수 있는 HttpSession을 제공한다
public static final String AUTHORIZATION_HEADER = "Authorization";
//세션 생성
@GetMapping("/create-session")
public String createSession(HttpServletRequest req) {
//servlet에서 요청이 들어왔을때 request객체를 만든걸 req로 받아오기
HttpSession session = req.getSession(true);
// .getSession(true); 세션이 존재할 경우 세션 반환, 없을 경우 새로운 세션을 생성한 후 반환
session.setAttribute(AUTHORIZATION_HEADER, "Robbie Auth");
// 세션에 저장될 정보 Name - Value 를 추가합니다.
return "createSession";
}


4. 세션을 가져와보자
public static final String AUTHORIZATION_HEADER = "Authorization";
//세션 가져오기
@GetMapping("/get-session")
public String getSession(HttpServletRequest req) {
// 세션이 존재할 경우 세션 반환, 없을 경우 null 반환 = 가지고 오는 거니까 또 생성할 필요는 x
HttpSession session = req.getSession(false);
String value = (String) session.getAttribute(AUTHORIZATION_HEADER);
// 가져온 세션에 저장된 Value 를 Name 을 사용하여 가져옵니다.
System.out.println("value = " + value);
return "getSession : " + value;
}

'Spring > Springboot-Intellij' 카테고리의 다른 글
[SpringBoot] Bean 수동 등록, 같은 타입 Bean이 2개인 경우엔? (0) | 2025.02.03 |
---|---|
[SpringBoot] JPA CORE - JPA란 무엇일까? (0) | 2025.01.31 |
[SpringBoot] Spring MVC - Path Variable과 Request Param (0) | 2025.01.30 |
[SpringBoot] Spring MVC - Jackson, ObjectMapper (0) | 2025.01.30 |
[SpringBoot] Spring MVC - 데이터를 Client에 반환하는 방법(JSON), RestController (0) | 2025.01.30 |