TIL React | 회원가입/로그인 -1

Taewoong Moon·2021년 6월 7일
0

오늘은 모든 홈페이지에는 거의 무조건 있다는 회원가입/로그인에 대해서 알아보겠다. 모든 홈페이지에서 회원가입/로그인 기능이 있기 때문에 비전공자 입장에서는 구현이 그리 어렵지 않을 거라 생각했지만....

태초마을로 가서 회원가입/로그인의 초기부터 살펴보자.

회원가입

회원가입을 할 때에는 요즘에는 OAuth를 통해 (즉, 소셜로그인)을 통해서 많이 하지만 전통적인 방식에서는 아이디/패스워드를 입력하고 회원가입을 등록을 했다.

그 과정에서 비밀번호를 개발자들이 알고 있다면 이것은 크나큰 문제가 될 수 있다. 보통 개인이 한 사이트에서 사용하는 ID 및 비밀번호는 다른 사이트들에서도 사용될 수 있기때문에 서버를 관리하는 개발자들이 개인정보를 남용할 수 있는 경우의 수가 높아진다.

그래서! 비밀번호를 입력해서 DB로 받을 때 비밀번호는 해쉬함수를 통해서 암호화가 된다. 해쉬는 비밀번호를 랜덤한 숫자 및 문자로 변환시켜 서버에서 데이터를 받을 때 랜덤한 형태로 숫자로 return되는 역할을 해준다.

암호화의 종류에는 양방향과 단방향 두가지로 나뉘었다.

양방향에는 암호화와 복호화(인코딩된 번호를 원래 번호로 디코딩하는 프로세스)가 있었는데

보안이슈와 해쉬가 나온 이후부터는 복호화에 대한 개념이 회원가입에서는 필요없어졌다.

단방향 암호화에는 3가지 방식으로 크게 나뉘어진다.

Session/ Token/ Token & Refresh 방식

-> Session : 세션은 유저가 회원가입 정보를 입력해서 서버에 저장하는 방식을 말한다. 기존에는 이렇게 하게 되면 2가지 문제점이 생긴다.

  • 확장성에 문제가 생긴다. 확장성 문제란 회원가입 정보를 서버에 저장하면 특정 서버에만 저장이 된다. 그렇다면 로그인을 시도할 때마다 백엔드 쪽에서는 특정 서버를 통해서만 인증이 가능하다는 이야기인데, 그 서버안에 갑자기 엄청많은 유저가 한번에 인증을 시도한다면? 바로 서버 과부화가 발생하면서 서버가 down되는 현상까지 발생할 수 있다. 물론 똑같은 서버를 여러개 만들어서 샤딩을 할 수 있지만 그 과정자체가 복잡하다.
  • 서버 과부화 문제가 생긴다.적은 데이터량은 받은 서비스라면 문제가 없겠지만 페이스북과 같은 대형회사라면 어마어마한 유저 인증정보가 세션에 저장이되고 서버과부화 현상이 일어날 수 밖에 없다.

Session의 특징: 상태를 서버에 저장하고 그 기반으로 움직인다.

-> Token: 해당 문제점을 해결하기 위해서 나온 게 Token이다. 토큰은 stateless, 즉 상태유지를 하지 않는다는 점에서 굉장히 유용하다. 토큰은 로그인 정보를 기입하면 서버에서 토큰을 발급한다. 이 과정에서 토큰은 DB에 인증정보를 저장하고 로그인할 때마다 원하는 서버에 정보를 저장시키고 클라이언트에 뿌려준다.

  • Token 형식은 저장을 만약에 DB에도 하지 않는다면 과부화 문제도 없다 (다만, 현업에서는 DB에 보통 저장을 한다).
  • 또한, 특정 서버에 접근해야만 데이터인증을 받을 수 있는 구조가 아니기 때문에 유동적으로 어느 서버에서든지 인증을 진행 할 수 있다.

Token 과정을 요약하자면,

  1. 유저가 아이디와 비밀번호를 로그인 하면,
  2. 서버에서는 아이디와 비밀번호를 확인한 이후에 토큰을 발급한다.
  3. 발급된 토큰을 클라이언트 local 저장소에 저장해서 요청을 할때마다 http headers파트에 같이 보내준다.
  4. 받은 토큰을 기반으로 서버에서 response를 한다.

여기서 더 추가된게 Token & Refresh 토큰 방식이다.

특정시간이 지나면 Token을 만료시키고, 만료연장을 한다면 토큰을 refresh해서 보내주고 해당 토큰으로 request & response를 한다.

Token을 만료시키는 이유는 보안의 문제가 가장 크다고 생각한다. 특정 유저가 우연의 일치로 accessToken을 맞추더라도 특정시간이 지나면 token이 만료되는 형태로 보안을 높이는 것이다.

로그인과정에서 토큰을 받아내고 그 토큰을 받아서 어떻게 전역에 적용시킬 수 있는지 코드를 통해서 다시한번 복기해보자.

회원가입 같은경우는 특별한 파트는 없다. 그냥 백엔드에 mutation을 통해서 원하는 값들을 전달해 주면 된다. 그리고 저장된 id/password를 로그인할 때 조금 다르다.

-> mutation을 활용하여서 로그인페이지에서 accessToken을 받아내야한다.
-> 해당 accessToken을 app_tsx에서 활용해서 모든 컴포넌트에 적용되어 headers에 포함되어야한다.
-> 그렇기 때문에 여기서 전역변수가 활용된다. (Context API)

export const GlobalContext = createContext({
	accessToken: '',
  	setAccessToken: (_: any) => {}
})

function MyApp({Component, pageProps}: AppProps) {
	const [accessToken, setAccessToken] = useState('')
	const uploadLink = createUploadLink({
      uri: '....',
      headers: {
        authorization: `Bearer ${accessToken}`
      }
    })
  
    return(
    //여기서 ContextAPI를 적용시킬 곳을 선택한다. 
      <GlobalContext.Provider value = {{accessToken: accessToken, setAccessToken: setAccessToken}}>
      <ApolloProvider client = {client}>
        <Component {...pageProps}>
      </ApolloProvider>
</GlobalContext.Provider>
    )

이렇게 전 컴포넌트에 지정해준후에 원하는 state를 자식컴포넌트에서 바꿔도 부모컴포넌트에서 사용할 수 있다.

setAccessToken이 바뀌고 로그인을 할 때 변경되면 끝!!!

원하는 페이지에서 로그인되있는지 안되어있는지 확인하는 방법은
useEffect를 통해서 걸러낼 수 있다.

이런식으로 써줄 수 있다. 그런데 페이지가 생길 때마다 이렇게 써주는건 조금 비효율적이어보인다. 그래서 다음에는 HOC(Higher order component)를 통한 권한분기에 대해서 좀 더 자세하게 알아보겠다.

회원가입/로그인에대해서 알아보았는데 굉장히 재밌다!!

아직 추가하지 못한 부분이 많다. 예를 들어서, validation 파트에서 정규표현식을 활용해서 걸러내는 방법 이런 부분들도 조금 더 꼼꼼하게 하나씩 추가해볼 생각이다.

profile
모든 코드에 의미를 담겠습니다.

0개의 댓글