인증
인증은 해당 유저가 실제 유저인지 인증하는 개념
지문인식, 로그인등등 실제 유저가 맞는지 확인하는 절차
인가
해당 유저가 특정 리소스에 접근이 가능한지 확인하는 개념
관리자 페이지에 접근시 관리자 권한이 있는지 확인하는 절차
웹은 보통 서버- 클라이언트 구조로 되어있음
Http 프로토콜을 이용해서 통신하는데, Http는 비연결, 무상태임
근데 실제로 인터넷을 사용하면 모든 정보들이 연속적으로 느껴짐
이는 사실 url을 계층적으로 설계하고있기 때문
그렇다면 인증상태 유지는 어떻게 하는건가??
인증의 방식
보통 웹 애플리케이션은 두 가지 방법을 통해서 인증을 처리함
쿠키-세션 방식
특정 유저가 로그인 되었다는 상태를 저장하는 방식
인증과 관련된 약간의 정보(Sesstion Id)를 서버가 갖고, 유저도 어느정도의 인증 정보를 갖고 로그인을 유지함
JWT 기반 방식
Json Web Token라는 인증에 필요한 정보를 암호화한 토큰을 사용함
JWT 기반 인증은 쿠키/세션 방식과 유사하게 JWT토큰을 HTTP 헤더에 실어 서버가 클라이언트를 식별하게 함
쿠키와 세션 모두 HTTP에 상태 정보를 유지하기 위한 도구임
서버는 쿠키와 세션을 이용해서 클라마다의 인증/인가를 할 수 있게 됨
쿠키
클라이언트에 저장될 목적의 작은 정보 파일
구성오소로는 다음 5개 요소가 있음.
Name : 쿠키 PK
Value : 쿠키 값
Domain : 쿠키가 저장된 도메인
Path : 쿠키가 사용되는 경로
Expires : 쿠키 만료기한
세션
서버에서 일정시간동안 클라이언트 상태를 유지하기 위한 것
서버에서 클라이언트 별로 유일부이한 세션 ID를 부여하고, 클라이언트 별 필요한 정보를 서버에 저장함
세션 ID는 클라이언트의 쿠키값(세션 쿠키)로 저장되어 클라이언트 식별에 사용됨
즉, 클라이언트가 서버에 인증을 요청하면 서버는 쿠키에 세션 ID를 담아서 전달함.
클라이언트는 해당 세션 ID를 쿠키에 저장하고, 다음 요청시 세션 ID를 포함함
서버는 해당 세션 ID를 보고 동일한 클라이언트임을 파악함
쿠키 생성
public static void addCookie(String cookieValue, HttpServletResponse res) {
try {
cookieValue = URLEncoder.encode(cookieValue, "utf-8").replaceAll("\\+", "%20");
Cookie cookie = new Cookie(AUTHORIZATION_HEADER, cookieValue); // Name-Value
cookie.setPath("/");
cookie.setMaxAge(30 * 60);
res.addCookie(cookie);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage());
}
}
new Cookie(AUTHORIZATION_HEADER, cookieValue);
쿠키에 저장될 Name과 Value를 생성자로 받는 Cookie 객체를 생성
setPath("/"), setMaxAge(30 * 60)
Path와 만료시간 지정
res.addCookie(cookie);
생성한 Cookie 객체를 HttpServletResponse 객체에 추가하여 브라우저로 반환함
쿠키 읽기
public static final String AUTHORIZATION_HEADER = "Authorization";
~
@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를 가져옴
세션 생성
@GetMapping("/create-session")
public String createSession(HttpServletRequest req) {
HttpSession session = req.getSession(true);
session.setAttribute(AUTHORIZATION_HEADER, "Robbie Auth");
return "createSession";
}
HttpSession session = req.getSession(true);
세션이 존재하면 해당 세션을 반환하고, 없으면 생성하고 반환
session.setAttribute(AUTHORIZATION_HEADER, "Robbie Auth");
세션에 저장될 정보 Name - Value를 추가함
세션 읽기
@GetMapping("/get-session")
public String getSession(HttpServletRequest req) {
HttpSession session = req.getSession(false);
String value = (String) session.getAttribute(AUTHORIZATION_HEADER);
System.out.println("value = " + value);
return "getSession : " + value;
}
HttpSession session = req.getSession(false);
세션이 존재하면 세션을 반환하고, 없으면 null을 반환함.
session.getAttribute(”세션에 저장된 정보 Name”)
Name을 이용해서 세션에 저장된 Value를 가져옴
JWT
Json Web Token
JSON 포맷을 이용해서 사용자에 대한 속성을 저장하는 Claim 기반 Web Token
일반적으로 쿠키 저장소를 사용해서 JWT를 저장함
JWT 사용 이유
서비스 운영을 위해서 여러대의 서버가 운영될 수 있음
이때 각 서버가 각 클라이언트의 정보를 갖게되면, 특정 클라이언트가 타 서버에 접속하면 문제가 발생함.
이를 위해서 세션 저장소를 생성하거나, JWT를 사용해서 클라이언트가 어떤 서버에 접속하던 API 요청을 처리할 수 있게 함
세션 저장소는 말 그대로 저장소고, JWT를 사용하는 방식은 다음과 같음
로그인 정보를 JWT로 암호화하여 Client에 저장하고, JWT를 통해서 인증/인가를 하는것임.
이때 모든 서버는 동일한 Secret Ket를 소유함
장점
동시 접속자가 많을 시 서버의 부하를 낮춤
Client와 Server가 다른 도메인을 사용할때 좋음
단점
구현이 어려움
JWT에 담는 내용이 커질수록 네트워크 비용이 증가함
JWT의 일부 만료가 불가능함
Secret key 유출시 JWT 조작이 가능함
JWT 사용 흐름
Client가 username, password로 로그인 성공 시
서버에서 로그인 정보를 JWT로 암호화함.
서버에서 직접 쿠키를 생성해 JWT를 담아 response에 전달. 이때 방식은 개발자 맘임
브라우저 쿠키 저장소에 JWT가 저장됨 자동으로
Client에서 JWT 통해 인증방법
서버에서 API 요청마다 쿠키에 포함된 JWT를 찾아서 사용함.
서버는 Client가 전달한 JWT의 위조 여부를 검증함.
서버는 JWT 유효 기간이 지나지 않았는지 검증함.
검증 성고시, JWT에서 사용자 정보를 가져와 확인함
JWT 구조
https://jwt.io/여기를 보면 잘 나옴
Header - Payload - Signature로 구성됨
Header와 Signature에는 암호화 관련 정보 양식을, PayLoad네는 유저 정로를 담음