의문점 공부하기/🧾공부하며

🧾로그인에 대해 ++

아리빠 2023. 10. 9. 20:57

클라이언트 사이드 vs 서버사이드

소셜로그인을 구현하는 방법은 크게 두 가지다. 하나는 클라이언트 사이드에서 플랫폼과 정보를 주고 받는 것이고, 다른 하나는 서버사이드에서 정보를 주고 받는 것이다.

 

클라이언트 사이드는 1) 클라이언트에서 정보를 플랫폼에 발송 2) 플랫폼에서 클라이언트로 토큰 발송 3) 클라이언트에서 서버로 토큰 전달 4) 서버에서 토큰을 가지고, 플랫폼에 유저 정보를 요청 5) 유저 정보와 서버에서 생성한 자체 토큰을 클라이언트로 전달하는 과정으로 진행된다.

 

서버 사이드는 1) 클라이언트에서 정보를 플랫폼에 발송 2) 플랫폼에서 서버로 토큰 발송 3) 서버에서 토큰을 가지고 플랫폼에 정보 요청 4) 유저 정보와 서버에서 생성한 자체 토큰을 클라이언트로 전달하는 과정으로 진행된다.

클라이언트 사이드로 구현하면, 단순하고 직관적으로 정보를 주고받기 때문에, 손쉽게 로그인을 구현할 수 있다.

 

 

하지만 클라이언트 사이드로 구현한 경우에는 몇 가지 한계가 있다. 첫째, 유저가 클라이언트를 사용하고 있을 경우에만 구글 API에 접근할 수 있다. 즉, 사용자가 웹 앱을 떠나면, 작업이 중단될 수 있다. 서버 사이드로 구현한 경우에는 사용자 대신 백그라운드 작업을 수행할 수 있다. 둘째, 구글 iframe이 특수 쿠키를 사용하여 구글 계정을 표시하므로, 브라우제어서 타사 쿠키를 비활성화한 경우 로그인이 동작하지 않을 수 있다.


JWT 인증절차

 

1. [프론트] ID와 PWD를 준다

2 . [백] ID와 PWD를 검증하고 AcessToken과 RefreshToken, AcessToken의 만료시간을 반환

3. [프론트] 반환받은 AcessTokend을 매 api 호출마다 헤더에 붙여서 전송

4. [백] api 호출시 헤더의 AcessToken을 확인하고 유효한지, 만료기간이 지났는지 체크 후 api 동작시킨다

5. [프론트] AcessToken의 만료기간이 지났거나, 30초 미만으로 남았다면, 백엔드에 RefreshToken을 붙여 Reissue 요청을 보낸다 

6. [백] Reissue 요청이 들어올 경우, RefreshToken이 DB에 있는 것인지 확인 후, 맞다면 AcessToken과 새로운 AcessToken만료시간을 반환

7. [프론트] Reissue결과 반환된 AcessToken과 만료기간을 저장하여 다음 api 호출에 사용 

 


<토큰에 대하여>
토큰에는 access토큰과 refresh토큰이 있다.
Access Token(JWT)를 통한 인증 방식의 문제는 만일 제 3자에게 탈취당할 경우 보안에 취약하다는 점이다.유효기간이 짧은 Token의 경우 그만큼 사용자는 로그인을 자주 해서 새롭게 Token을 발급받아야 하므로 불편하다. 그러나 유효기간을 늘리자면, 토큰을 탈취당했을 때 보안에 더 취약해지게 된다.


이때 “그러면 유효기간을 짧게 하면서 좋은 방법이 있지는 않을까?”라는 질문의 답이 바로 "Refresh Token"이다.
Refresh Token은 Access Token과 똑같은 형태의 JWT이다. 처음에 로그인을 완료했을 때 Access Token과 동시에 발급되는 Refresh Token은 긴 유효기간을 가지면서, Access Token이 만료됐을 때 새로 발급해주는 열쇠가 된다.(여기서 만료라는 개념은 그냥 유효기간을 지났다는 의미이다.


예를들어, Refresh Token의 유효기간은 2주, Access Token의 유효기간은 1시간이라 한다면, 사용자는 API 요청을 하다가 1시간이 지나게 되면, 가지고 있는 Access Token은 만료된다. 그러면 Refresh Token의 유효기간 전까지는 Access Token을 새롭게 발급받을 수 있다.
따라서 최근에는 이 두개를 혼용하는 방법을 많이 사용하고 있다.


쿠키 헤더에 담아 서버에 보내주기

 

axios의 config방식

//axios 요청방법
axios.get('url')

//config로 GET 요청
//axios.get({url, data, config}) 형식으로 작성
axios({
  method: 'get',
  url: 'url',
  headers: 
  'Content-Type':'application/json',
  'X-Requested-With': 'XMLHttpRequest',
})
  .then((response) => {
			console.log(response);
  });

//config로 post요청
// axios.post({url}, {data}, {config}) 형식으로 작성 
axios.post('url', // 미리 약속한 주소
	{name: 'perl', status: 'cute'}, 
	{headers: {'X-Requested-With': 'XMLHttpRequest'}} 
).then(function (response) {
    console.log(response);
####   })
  .catch(function (error) {
    console.log(error);
  });

헤더에 토큰 담기
//default
 {headers: { 'Authorization': '내 토큰' },} 
//내코드 
headers: {
        authorization: `Bearer ${getCookie("is_login")}`,
      }
      
이때, authorization은 서버에서 설정함에 따라서 대문자가 될수도 있고, 
소문자가 될수도 있고 하니 백엔드와 사전에 맞추는 작업이 필요하다고 한다. 
서버에서 authorization이라고 설정을 해놓았는데 프론트 쪽에서 Authorization이라고 보낼경우 헤더에서는 undefined로 인식된다고 한다.

토큰 앞에는 bearer가 붙는다. bearer가 없다고 해서 문제가 되지 않고, 서버쪽에서도 바로 토큰을 받을 수 있다는 장점이 있지만, bearer를 사용하는건 암묵적 약속이라고 한다.

 

로그인 유지하기
우선 리액트는 새로고침시마다 스테이트가 초기화 된다. 따라서 로그인을 유지하기 위해서는 해당페이지가 렌더링 될때 토큰 값을 가져와서 서버로 토큰을 보내 토큰이 유효한지 확인하는 과정을 거쳐야 한다.
유지하는 과정은 아래와 같이 구현하였다.

쿠키에 토큰이 저장되어있는지 확인 --> 헤더에 토큰담아서 get요청보내기 (유효한 토큰인지 검증하기) --> 검증성공시 페이지 보여주기
만약 검증이 실패한다면, 로그인 페이지로 이동하도록 설정