브라우저에서 철수가 input을 입력하고 login을 누르게 되면 백엔드로 전송
그 후에 철수가 결제하기 api요청을 요청하면 login한 사람과 철수가 같은 사람인지 어떻게 구분할까?
만약 상품등록을 할 경우 memory에 session이라는 변수에 uuid같은 id값을 주고 로그인 정보를 저장하여
브라우저에 있는 id와 session의 id를 비교하여 같을 경우 상품등록이 가능하도록 하였다.
문제점은 사용자가 많을경우 memory session의 데이터가 많이 들어오게되고 백엔드 컴퓨터 한대에서 많은 api를 memory에 저장해놓고 하나씩 처리해야하기 때문에 비효율적이다. RAM을 16G 32G scale up 하더라도 근본적인 문제를 해결할 수 없다.
또 다른 방법으로 백엔드 컴퓨터를 여러대 두어 소스코드를 공유하여 사용하는 방법도 있다 이를 scale out 이라고 한다.
하지만 로그인 memory session(stateful)은 공유되지 않기 때문에 다른 백엔드 컴퓨터에 상품등록같은 api를 요청하게되면 id 검증이 불가능하다. 이러한 memory session이 없앤 경우(stateless)라고 한다. 현재 로그인 방식이 memory session을 사용하지 않는 stateless 이다.
백엔드 컴퓨터가 여러대 있을 때 백엔드를 stateless 상태로 만들고 DB에 토큰id(session id와 같은 말)를 줘서 로그인 정보를 저장한다.
백엔드에서는 브라우저에 저장된 id값과 db의 토큰id 값을 비교해서 api요청을 받아준다. 그러나 DB로 부하가 몰리기 때문에 이 또한 좋은 방법이 아니다.
해결책으로 DB를 늘려보았으나 많은 토큰 로그인 정보를 공유해야하기 때문에 좋은 방법은 아니었다.
그 다음 해결책으로 로그인정보가 담긴 테이블을 여러대의 DB로 나누는 방법이 나왔다.
테이블을 가로(수평 파티셔닝,샤딩)로 나누어 여러 DB 컴퓨터에 저장한다.
누군가 createProduct를 백엔드에 요청하게되면 백엔드에서 DB에 저장된 로그인 정보와 브라우저에서 온 로그인 정보를 비교하고 Br로 data를 보내주게된다.
여기서 발생하게 되는 문제는 로그인 정보가 DB 디스크(영구저장공간)에 저장되어있는데 이 방법은 저장도 오래걸리고 전송과정에서도 오래걸린다. 이를 전문적인 용어로 DB를 긁는다고 표현하는데 성능적인 면에서 메모리에 비해 많이 느릴 수 있다.
이를 해결하기위해 DB 메모리 저장공간 Redis에 저장하게되면 성능 문제를 어느정도 해결할 수 있다.
또 다른 방법으로는 Redis에 조차도 저장하지 않는 방법이 연구가 되었다.
객체를 하나 만들어놓고 id는 지우고 안에 있는 name과 유효기간을 암호화하고 암호화의 정보를 id로 사용하는 방법이다. 그래서 로그인 정보가 필요하면 다시 복호화해서 마치 DB에서 받아온것처럼 사용하는 방법이다.
{
id:afsf,
name:"철수",
exp:~2022
}
이렇게 암호화된 토큰을 JWT(Javascript Object Notation)토큰이라고 한다. 브라우저에서 email/pass를 보내면 백엔드를 통해 DB에 정보를 확인하고 백엔드에서 다시 객체로 만들어 암호화된 토큰을
브라우저에 state를 저장한다.
그 후에 사용자가 브라우저에서 createProduct 와 같은 api를 요청할때 tokenID까지 같이 보내게 된다. 이렇게되면 api요청이 올때마다 DB까지 가서 검증할 필요가 없어진다.
JSON Wep Tokens 홈페이지에 들어가서 확인해보면
SIGNATURE는 암호화에서 복호화할때 필요한 비밀번호 같은 개념이고
PAYLOAD에는 우리가 원하는 방식으로 객체를 만들수 있다.
iat를 추가해서 만들어줬을 때 만든 시간을 의미한다.
exp는 로그인 만료시간을 의미하고
객체의 내용을 변경하면 Encoded의 내용이 바뀌게된다.
JWT 토큰은 암호화한것처럼 보이지만 누구든지 안에 내용을 확인할 수 있다. 그렇기 때문에 JWT 안에는 계좌번호나 포인트같은 중요한 정보를 저장하면 안된다.
누구나 조회는할 수 있지만 PAYLOAD의 데이터는 SIGNATURE 때문에 수정할 수 없다.
헤더부분에 인가를 해주면 HTTPS 헤더 부분에 해당하는 암호화 id를 받아줄수있다.
인증(Authentication) : login 하는 과정에서 email과 password를 보내주고 accessToken을 받아오는 것
인가(Authorization) : 이미 가지고 있는 Token을 가지고 api를 사용할때 acessToken을 api통해 백엔드로 보내주고 복호화되어 사용
Bearer: 큰의미가 있는 것은 아님 단순 문자열로 백엔드에서는 replace 함수로 Bearer만 제거하고 Token을 사용
DB에 email password name을 저장하게 되는데 해커가 DB를 해킹할 수 있기 때문에 password를 암호화해서 저장한다. 하지만 암호화로 저장해도 해커들은 복호화해서 사용하기 때문에 암호를 다시 복호화할 수 없도록 단방향 암호화(Hash)를 해줘야한다. 복호화가 가능한것은 양방향 암호화라고 한다.
단방향 암호화(Hash)는 숫자 172638 이라고 할때 두자리씩 끊어서 768을 비밀번호로 저장한다 이를 복호화했을때 172638이 나올 수 없게 된다.
유저가 비밀번호 찾기를 했을 때 보통은 새로운 비밀번호를 입력해줘야하는 홈페이지가 그나마 정상적인 페이지이다.
하지만 해커들이 슈퍼컴퓨터로 768을 이용하여 모든 경우의 수 따져서 복호화하기 때문에 완전한 방법은 아니다. 창과 방패의 대결이므로 모든것을 막을 수 없다.
인풋값으로 이메일과 패스워드를 입력하고 로그인 버튼을 누르면 로그인 api를 보내고
받아오는 Token을 state에 저장한다. 그 후에 useQuery로 fetchUserLoggedIn api로 데이터를 받아와 사용해본다.