티스토리 뷰

반응형

React로 웹을 만들면 필연적으로 서버와 접속하게 됩니다. 이 때 서버는 직접만든 서버일 수도 있고 외부에서 제공한 서버 일 수도 있는데요. Public게 오픈되어지는 서버라면 상관없지만, 유효한 유저의 요청일 경우만 반환하는 것이 일반적입니다. 날씨정보를 가져오더라도 유료화 모델의 경우 특정 유저는 더 많은 API를 사용할 수 있도록 권한을 부여한다던지 하는 것도 이러한 Role 기반의 비즈니스 모델이지요.

오늘 제가 소개해드릴 것은, 직접만들 서버에 요청하는 API는 반드시 유효한 인증정보를 담고 있어야 하고, 그 인증정보가 유효한지 서버에서 체크한 뒤 만약 유효한 유저라면 그에 상응하는 응답을 하는 기본적인 로직구현을 해보도록 하겠습니다. 아마도 이 부분은 리액트에서 API 부를 구현하는 분이 모듈레이션을 잘 해놓는다면 컴포넌트를 만들거나 할때 로긴과, 인증정보를 아에 신경쓸필요 없이 펑션콜처럼 불러쓰면 API 통신이 되는것처럼 하는게 가장 베스트이겠지요.

먼저 아래 글을 읽지 않으셨다면 한번 쓱 읽어보고 진행하겠습니다.

https://hero-space.tistory.com/106

 

React 에서 REST API 요청하기 (feat.AXIOS, react-query)

프론트앤드는 하나의 클라이언트로서 서버와 통신을 통해 데이터를 받아오고 이를 시각화 하는 역할을 보통합니다. 서버는 사용서버일 수도 있고 자신이 만든 서버일 수도 있는데요. 리액트에

hero-space.tistory.com

인증서버 구축

인증서버는 자신의 서버에 직접 만드는 방법이 있고, 흔히 많이 쓰는 방법으로 파이어베이스의 인증모듈을 사용하는 방법이 있습니다. 인증의 가장 큰 요소는 OAuth이고 다시말해 토큰인데, 가입하여 로그인한 유저에게 토큰을 발급해 주고, 이 토큰을 갱신하고, 또는 리보크하고 하는 토큰매니지먼트 기능을 파이어베이스에 해주기 때문에 파이어베이서 인증모듈을 이용하거나, 이러한 것들을 자신의 서버에 직접 구현하면 됩니다. 당연히 저는 혼자하고 있기 때문에 파이어베이이스의 인증모듈을 활용해서, 가입한 유저가 로그인할 경우 토큰을 받아왔다고 가정하고 진행하도록 하겠습니다.

파이어베이스는 Javascript용 SDK를 제공하고 있어서 편하게 리액트에서 이용할 수 있습니다. 아만 API 9와 API 8 버전이 있으니, 선택해서 한가지로 하시면 되는데요. 저는 최신의 것들을 선호하다보니 API 9 버전으로 진행하도록 하겠습니다. 

https://firebase.google.com/docs/reference/js

 

API Reference  |  Firebase JavaScript API reference

The Firebase JavaScript SDK implements the client-side libraries for applications using Firebase services.

firebase.google.com

다만 거기에 조금더 나아가서 react-firebase-hook 패키지를 이용해볼까 하는데요. 인증서버의 역할을 하는 파이어베이스와 비동기 통신을 하다보니 상태변화를 감지하는 코드등을 직접작성하게 되는데 이를 내포하고 있기 때문에 조금 더 간결하게 개발을 진행할 수 있습니다.

https://www.npmjs.com/package/react-firebase-hooks

 

react-firebase-hooks

React Hooks for Firebase. Latest version: 5.1.1, last published: 3 days ago. Start using react-firebase-hooks in your project by running `npm i react-firebase-hooks`. There are 47 other projects in the npm registry using react-firebase-hooks.

www.npmjs.com

API와 Token

서버역시 firebase의 인증 모듈을 쓰도록 규약했기 때문에, Firebase 를 통해 로그인을 한 유저의 token을 api header에 싣어서 보내면 이를 유효한지 유효하지 않은지 서버는 알수 있습니다.  다만, 서버에서 제공하는 API 셋드을 구현해놔야 하고, 이 API를 사용할 때 로긴한 currentUser의 토큰정보가 자동으로 들어가도록 레이어화 하면 좋겠다는 생각이 들었는데요. 아래와 같이 해보았습니다.

client.ts 

import { firebaseAuth } from '@services/Firebase/fbase';
import axios from 'axios';

const apiClient = axios.create({
  baseURL: `${process.env.REACT_APP_API_URL}/api/v1`,
});

const getAuthToken = async () => {
  try {
    return `Bearer ${await firebaseAuth.currentUser?.getIdToken(true)}`;
  } catch (err) {
    console.log('getAuthToken', err);
    return Promise.reject(err);
  }
};

apiClient.interceptors.request.use(
  async (config) => {
    const cf = config.headers;
    cf['Content-Type'] = 'application/json';
    cf.Authorization = await getAuthToken();
    return config;
  },
  (err) => Promise.reject(err),
);

export default apiClient;

보시면 apiClient를 사용하게 되면 baseURL이 통해 기본 URI가 세팅되고, token은 실제 사용할때 interceptors에 의해 currentUser의 토큰을 넣어서 보내게 됩니다. FirebaseAuth는 firebase에서 제공하도록 분리해놓았구요. 

상세한 API 제작

API의 기본 구성이 완료되었다면, /user 라는 API를 호출하는 로직을 구현해보도록 하겠습니다.

user.ts

export default interface IUser {
  email: string;
  name: string;
  organization: string;
  tag: string;
}

먼저 규약된 json struct와 같이 API를 통해 리턴받을 내용으로 구성된 인터페이스를 생성합니다. 그리고 실제 userAction.ts에 아래와 같이 작성 해보도록 하겠습니다.

import apiClient from '@utils/client';
import IUser from '@api/User';

function UserActions() {
  return {
    getUser,
  };

  async function getUser() {
    const response = await apiClient.get<IUser>('/user');
    console.log('data', response.data);
    return response.data;
  }
}

export { UserActions };

이제 이런식으로 api를 추가하면 기본적으로 각 컴포넌트에서는 UserActions를 임포트 해서 getUser를 사용하면 로기한 유저의 토큰 기반으로 /user 리퀘스트를 서버로 보내서 리턴받은 결과를 확인 할 수 있습니다.

반응형
댓글