7편 - React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 로그인/회원가입

이전편에서 우리는 카드 상세 뷰를 구현해봤다. 이번편에서는 이전편에서 예고했듯이 사용자 인증 관련 로직(로그인/회원가입)을 추가 할 것이다. 이전 계획에서 변경된 부분이 있는데, auth0 서비스를 이용하지 않고, 기본적인 email/password로 인증을 구현 하는 것으로 변경 했으니 이점 유의하자.
참고: 이번 튜토리얼을 진행 하기 위해 진행 되는 코드를 깃헙에 업로드 해놨으니, 이 튜토리얼을 진행하고 싶다면 아래에서 소스를 클론 받은 후 아래의 내용을 따라가기를 추천 드립니다.
튜토리얼 소스:
https://github.com/simsim0709/react-apollo-flow-trello-clone/tree/ch-7
이전 편:
0편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 소개
1편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 프로토타입
2편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - graphcool (GraphQL 서버 만들기)
3편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - Trello Board 생성
4편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - Apollo 스토어 업데이트, Flow
5편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 리스트(List), 카드(Card) 6편 - React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 카드(Card) 상세 뷰

이번편의 작업 순서는 아래와 같다:
  • graphcool 백엔드서비스에 인증 로직 추가
  • apollo client 헤더에 인증 토큰 추가
  • 회원가입 컴포넌트 개발
  • 로그인 컴포넌트 개발

graphcool 백엔드서비스에 인증 로직 추가

우리는 authentication-with-email-and-apollo에 있는 소스를 기반으로 서버와 클라이언트를 구성해볼것이다.

참고

graphcool에서는 위의 예제 말고 다양한 샘플 예제를 제공한다: https://github.com/graphcool-examples/react-graphql/
또한, cli를 통해 템플릿을 추가 할 수 있는 패키지도 제공한다: https://github.com/graphcool/templates

사실, graphcool 서비스는 이전 버전에서는 다양한 써드파티 앱들과의 통합을 할 수 있도록 자체적으로 지원을 했었다. 하지만, graphcool 서비스가 프레임워크 기반으로 변경되면서 이러한 부분이 제거가 되고, 커스텀한 기능들을 서비스 이용자들이 직접 구성 할 수 있도록 변화 했다. 그래서 이메일/패스워드 인증로직을 추가하기 위해선 우리가 직접 서버 소스를 작성, 등록해서 이 소스를 graphcool 서비스에 업로드(deploy) 해주어야 한다. 결론적으로, 로그인/회원가입을 구성하기 위해서 필요한 작업은 총 4가지이다:
  • User type 추가
  • 로그인/회원가입 관련 resolver function과 type 구성
  • graphcool.yml에 등록
  • graphcool 서버에 업로드(deploy)

User type 추가

먼저, graphcool-server/types.graphql의 User type을 아래와 같이 변경한다:
type User @model { id: ID! @isUnique createdAt: DateTime! updatedAt: DateTime! name: String email: String @isUnique password: String }

로그인/회원가입 관련 resolver function과 type 구성

이 부분은 authentication-with-email-and-apollo 의 소스를 그대로 가져오도록 하겠다.

graphcool.yml에 등록

위에서 소스를 추가 했다고, graphcool에 이 resolver를 바로 사용 할 수 있는 것은 아니다. 우리가 추가한 소스를 graphcool.yml에 명확하게 매핑을 해줘야 우리가 추가한 커스텀 function을 사용 할 수가 있다.
graphcool.yml에 보면 functions property에 아래와 같이 추가한다:
signup: type: resolver schema: src/email-password/signup.graphql handler: code: src/email-password/signup.js authenticate: type: resolver schema: src/email-password/authenticate.graphql handler: code: src/email-password/authenticate.js loggedInUser: type: resolver schema: src/email-password/loggedInUser.graphql handler: code: src/email-password/loggedInUser.js
코드를 보는 것만으로 충분히 이해 할 수 있을 것이라고 생각 되는데, 우리가 추가한 파일과 역할을 yml 문법으로 추가해준것이다. 이에 대한 자세한 설명은 공식문서에 자세히 나와 있으니 추가적으로 이해가 필요한 부분은 공식문서를 참고하자.

graphcool 서버에 업로드(deploy)

자, 이제 모든 준비는 됐으니 graphcool 서버에 디플로이를 해보자. 디플로이 명령어는 앞에서도 몇 번 써봤으니 익숙 할 것이다(만약, 이전 튜토리얼을 따라해봤다면..)
cli에서 graphcool-server로 이동한 후:
graphcool deploy -f
에러없이 디플로이가 되었다면 성공 한것이다. graphcool playground에서 변경된 스키마(loggedInUser, signupUser, createUser)가 적용되었는지 확인해보자!
이제 서버는 모든 준비가 되었다. 이제 프론트엔드 개발을 해보자!

apollo client 헤더에 인증 토큰 추가

graphcool 서비스의 인증 로직은 http header에 authorization field의 값으로 Bearer token을 실어 보내는 것으로 인증을 구현한다.
그래서 우리가 할 일은 모든 graphql 오퍼레이션(query, mutation)에 token 값을 보내줘야 하는데, 이것을 처리 할 수 있는 곳은 ApolloLink이다.
아래의 변경된 소스를 보자:
// apolloClient.js
import { ApolloClient, ApolloLink, InMemoryCache, HttpLink, } from 'apollo-client-preset'; const httpLink = new HttpLink({ uri: process.env.REACT_APP_GRAPHCOOL_SIMPLE_API, }); const middlewareLink = new ApolloLink((operation, forward) => { const token = localStorage.getItem('graphcoolToken'); const authorizationHeader = token ? `Bearer ${token}` : null; operation.setContext({ headers: { authorization: authorizationHeader, }, }); return forward(operation); }); const httpLinkWithAuthToken = middlewareLink.concat(httpLink); const client = new ApolloClient({ link: httpLinkWithAuthToken, cache: new InMemoryCache(), }); export default client;
소스에 강조된 부분을 보면 ApolloLink에 operation.setContext를 이용해서 header 정보에 authorization field를 추가해서 graphcool에서 제공해주는 token 값을 추가해서 보내도록 변경해주었다.
자, 이제 크롬의 네트워크 탭을 열어서 리퀘스트 payload를 확인해보자.
authorization을 추가하기 전의 네트워크 Request Headers:
presentation

authorization을 추가한 후의 네트워크 Request Headers:
presentation
위의 스크린샷을 보면 request header 정보에 authorization이 추가된 것을 확인 할 수 있다.
자, 여기까지 무리없이 따라왔다면 인증 관련한 부분은 다 완료된것이나 마찬가지다. 이제는 우리가 계속해서 해왔던 리액트 컴포넌트를 만들어서 로그인/회원가입 리액트 컴포넌트를 만들기만 하면 된다. 우리에게 필요한 컴포넌트는 총 3개이다:
  • LoginButton: 버튼 컴포넌트로써 로그인전에 클릭하면 로그인/회원가입 다이얼로그 폼을 보여주고, 로그인 상태에서 클릭하면 로그아웃을 진행한다.
  • LoginForm: 이메일/패스워드 인풋 값을 보내서 인증에 성공하면 서버에서 받아온 token 값을 로컬 스토리지에 저장한다.
  • SignupForm: 이메일/이름/패스워드 인풋 값을 보내서 회원가입에 성공하면 서버에서 받아온 token 값을 로컬 스토리지에 저장한다.
graphql의 query와 mutation은 지금까지 튜토리얼을 통해 많이 연습해봤으니 별도의 설명은 생략하고 직접 위의 소스를 보면서 파악하는게 좋을 것 같다.

이번편에서는 이메일/패스워드를 활용한 기본적인 인증 로직을 구현해봤다. 다음편에서는 이렇게 적용된 인증로직을 통해 자기가 추가한 보드와 카드만 관리하는 로직을 추가해보도록 하겠다.