(JWT의 구조)세션,토큰과 인증,인가
JWT(Json Web Token)
JWT가 어떤 역할을 하고 왜 나왔는지 흐름대로 알고있는게 JWT에 대한 이해를 높이는데 도움이 될거라고 생각한다.
HTTP의 통신부터 알아보자
HTTP
HTTP는 클라이언트와 서버를 통신해주는 프로토콜이다. HTTP는 connectionless(비연결지향), stateless(무상태)라는 특징을 가지고 있다. 즉 유저가 사이트에 방문했을때 페이지를 눌러 새로운 화면을 보려고 할때마다 서버는 유저에게 원하는 데이터를 준 후 연결을 바로 끊게 된다.
연결이 끊기는 순간 서버는 상태정보를 저장하고 있지 않기 때문에 만약 유저가 로그인을 한 상태였다면 페이지를 전환할때마다 로그아웃이 되어버리는 셈이다.
HTTP의 문제를 해결하기 위한 세션과 토큰
위의 문제는 당연히 해결되어야 하는 문제다. 이를 해결하기 위해서 세션
과 토큰
이 사용된다.
세션(Session)
세션은 사용자의 정보를 브라우저에 저장하는 쿠키와는 다르게 서버측에서 정보를 관리하고 있다. 일정시간을 두어 그 시간동안 같은 사용자의 요청을 나의 상태로 보고 상태를 유지시켜준다.
하지만 사용자의 정보가 서버에 저장되면서 서버에 사용자가 몰릴 경우 서버 과부하로 다운이 될 수 있는 문제점을 가지고 있다. 여러 서버를 두고 사용자를 분산시키는 방법도 있지만 이럴 경우 세션을 쓰기가 꽤 복잡해진다. (다른 서버들에게 같은 유저라는 인증을 하는과정이 복잡하다)
토큰(Token)
세션의 단점을 보완할 수 있는 도구가 바로 토큰이다. 토큰은 사용자가 로그인을 하면 서버에서 로그인을 한 사용자의 정보를 함께 담아 사용자에 대한 토큰을 발급한다. 이후 토큰을 클라이언트측에 전송한다. 이후 사용자가 글을 작성하거나 자신의 글을 수정하기 위해 서버측에 요청을 보낼때 헤더에 발급받은 토큰을 함께 담아 요청을 보낸다.
이후 서버측에서는 받은 토큰을 시크릿키로 풀어 user의 정보를 확인한다. 이러한 과정으로 서버에서는 세션처럼 유저의 정보를 따로 저장해두고 있지 않아도 된다.
이 과정에서 주로 JWT라는 토큰이 사용되어지는 것이다.
인증(Authentication)과 인가(Authorization)
jwt를 사용하기 전 두개의 뜻을 정확하게 이해해보자.
인증
인증은 쉽게 말해 회원가입한 유저의 아이디와 비밀번호를 확인하는 절차를 말한다. 즉 로그인이 성공하면 해당 유저를 인증해줄 수 있는 토큰이 발급된다.
인가
인가는 이 유저에 대한 권한을 허락하는 절차이다. 글을 수정하려는 유저가 해당 글을 작성했는지 권한이 있는 유저인지를 확인하는 과정이라고 보면 된다.
그리고 유저는 인가를 받기 위해 자신을 인증할 수 있는 토큰을 사용한다
로그인을 하면 로그인 한 유저를 인증해줄 수 있는 토큰이 발급되고 해당 토큰을 가지고 유저는 접근 권한이 필요한(글 수정, 글 삭제 등) 곳에서 허가를 받는다.
JWT의 구조
처음 JWT를 접했을때 구조를 보고 블로그 글을 참고해도 와닿지 않는 느낌이 컸다. JWT가 대충 뭔지는 알겠는데 "그래서 저게 어떻게 사용되는데 ?"
딱 이런 마음이였다.
아마 개념을 확실히 이해했어도 직접 실습해보는것과 이해하는 깊이가 다를것이다. 개념만 보고 넘기지 않고 간단한 실습이라도 꼭 ! 해보았으면 좋겠다.
그럼 JWT의 구조를 알아보자.
JWT는 크게 3가지의 구조로 되어있다. 헤더(header)
, 정보(payload)
, 서명(signature)
-
header : 헤더에는 토큰의 타입과 데이터를 암호화할 해싱 알고리즘의 정보가 들어간다. 여기서 직접 해싱 알고리즘을 지정해줄 수 있다 (주로 sha256, rsa가 사용된다). 그리고 이 알고리즘은 signature에서 사용이 된다
-
payload : 이곳에는 토큰에 담을 유저의 정보가 들어있다. 유저가 로그인을 하게 될 경우 유저의 id등을 이곳에 담는다. 이곳에는 토큰의 만료시간등도 함께 넣어 줄 수 있다.
-
signature : 이곳에서는 위에서 작성한 header의 인코딩값과 payload의 정보의 인코딩값을 합쳐 시크릿키로 값을 해시하여 생성한다
그래서 나온 값이 이미지의 왼쪽에 있는 값들이다. 각 정보의 인코딩값 사이에는 .
이 들어가 있다.
이렇게 보았을때는 아리송하다. 우리는 개발자니까 코드를 보자.
만들어질 토큰에는 {}안에 있는 유저정보, 해시할 때 사용하는 시크릿키, 적용하려는 해시 알고리즘을 넣어서
만든다.
token = jwt.encode({'user_id': 12}, SECRET_KEY, algorithm='HS256')
이후 발급받은 토큰을 보내야 한다. 이때 인코딩된 토큰의 타입이 bytes 이기 때문에 문자열 형태로 바꾸어 전달해준다.
token.decode('utf-8')
서버에서 발급받은 token을 디코딩하면 유저의 payload 즉 정보를 반환받게 된다.
access_token = request.headers.get('Authorization', None)
payload = jwt.decode(access_token, SECRET_KEY, algorithms='HS256')
print(payload) # {'user_id': 12}
그럼 이제 JWT로 토큰을 발급받아 유저를 인가받는 실습을 해보자