TIL45⎟React : fetch 함수를 이용한 서버 인증 with BackEnd

itssweetrain·2021년 4월 10일
1

React

목록 보기
4/10
post-thumbnail

프론트와 백엔드의 처음 통신이후 더 구체적으로 구현해보고 싶다는 마음이 들었다.

회원가입부터 댓글달기 기능까지 인증 인가에 대한 개념을 정리하고 통신이 어떻게 이루어지는지, fetch 함수는 어떻게 이용하고 프론트엔드에서는 무엇을 보여줄 지 알게 되었다.

한번에 많은 것들을 하게 되어 추가하고 수정해야할 부분들이 있겠지만 기록으로 남겨본다.

💡 주요 구현 사항

1. 회원가입 & 로그인 인증 :
account, password 창에 입력한 값을 input에 onChange를 통해 값을 업데이트해주고, 이 정보를 서버로 보낸다. 보낸 후 서버로부터 인증된 유저에게 부여한 고유한 access token을 받아 local storage에 저장하게 했다.

2. 피드 게시물 생성 :
로그인을 한 인증된 유저만이 게시물 포스팅 시 내 피드에 게시물이 뜰 수 있게하는 것이 목표. 회원 인증/인가를 처리하기 위해 로그인 토큰을 Authorization에 담고, request header에 담아서 보냈다.

3. 댓글 달기 :
인증된 회원이 댓글을 입력하면 서버로 보내고, 다시 그 데이터들을 받아 프론트 화면에 띄우게 하였다.


글에서는 1,2번만 다뤄보도록 하겠다. 백엔드에서 필요한 것이 무엇이고, 프론트에서는 어떻게 구현해야하는지 마주한 문제들을 곰곰히 생각해보고 파헤쳐갔다.
  1. 먼저 어떻게 통신이 이루어지는 하나의 큰 흐름을 이해하는 것이 중요했다.
  2. 그 다음 백엔드로부터 정보를 주고 받기 위한 포맷(fetch 메소드)을 이해하는 것이 중요했다.

POST와 GET을 쓸 때는 정확히 언제인지, POST일 때 보내줄 정보들에는 무엇이 담기는지, 어떤 형식으로 보내야하는지. 이런 데이터의 요청과 응답이후 프론트 화면에서는 어떤 것들을 구현해낼지까지 하나의 흐름을 이해했다.


1. 서버 인증의 흐름

(토큰 기반 인증 방식)

  1. 회원가입 후, 사용자가 로그인 한다.
  2. 서버에서는 저장된 데이터들을 비교대조하여 사용자를 확인 후, 일치하면 사용자의 고유한 access token 값을 부여하여 보낸다.
  3. access token을 받아 local storage에 저장 후, 인증이 필요한 요청마다 이것을 HTTP header에 실어 보낸다.
  4. 서버에서는 이 정보를 받아 저장소에서 대조를 한 후 결과를 응답(Response)로 보내주고 대응되는 정보를 가져온다
  5. 인증이 완료되고 서버는 사용자에 맞는 데이터를 보내준다.

2. fetch 사용법

fetch("url", {method: "", body:JSON.stringify({}),등 options})
.then (res => res.json())
.then (res => {})

options 객체에는 HTTP방식(method), 요청 헤더(headers), 전문(body)등을 설정해줄 수 있다.

여기서 헤더에는 요청에 대한 정보들이 들어간다. 보통 모바일/웹 서비스의 인증은 헤더에 인증 수단을 넣어 요청을 보내게 된다. 바디에는 서버로 보내야할 데이터가 간다. 생성/변경된 데이터를 보내기 위해 사용된다.

fetch 로 API 주소를 받아온 다음, method가 GET이면 받는 역할만 하므로 headers나 body가 필요없게 된다. method가 POST면 다시 해당 API로 데이터를 보내줘야하므로 작성이 필요하다.

.then은 fetch에서 작성한 것들이 모두 끝나고 난 후, 실행될 코드들이다. 통신은 다른 로직에 비해 시간이 오래걸리기에 비동기 처리가 되어 then 메소드를 써주는 것이다.

API 호출이 성공했을 경우는 응답(res)을 resolve하고, 실패했을 경우는 예외(error) 객체를 reject하는 Promise 타입의 객체를 반환한다. 여기서는 예외 옵션은 일단 생각하지 않기로!

데이터들을 다시 JSON 파일로 받아와 자바스크립트의 객체로 변환하여 볼 수 있다. 이 데이터들로 프론트에서 화면에 출력할 것을 위한 식들을 작성해주면 된다.


1. 로그인 구현

로그인 api에서는 로그인이 성공하면 백엔드에서 jwt로 만든 access token을 받는다. 프론트엔드에서는 이 access token을 local storage에 보관하다가, 사용자 정보가 필요한 api를 호출할 때 해당 토큰값을 보내줘야한다. 이것을 피드 게시물 생성할 때 보내주었다.

  1. access token을 local storage에 저장하기
    local storage는 해당 도메인에 영구 저장하고 싶을 때 저장하는 곳이다. 여기서는 한 번만 로그인하면 값이 계속 저장된다. localStorage.setItem() 메소드를 이용하였다.

  2. fetch 함수를 담은 함수를 따로 만들어 onClick 함수 안에 넣어주었고, 로그인 버튼을 클릭할 때 onClick 함수안에서fetch 함수를 통해 서버에 요청(Request)을 보낸다. 서버에서는 인증 인가 과정을 거친 후 결과를 응답(Response)로 보내주고, 응답을 결과에 따라 환영창과 함께 메인페이지로 넘어가도록 구현했다.

checkValidation = () => {
    const { loginId, loginPw } = this.state;
    fetch("IP주소", {
      method: "POST",
      	body: JSON.stringify({
        account: loginId,
        password: loginPw,
      }),
    })
      .then((res) => res.json())
      .then((data) => {
        if (data['MESSAGE'] === 'SUCCESS') {
          localStorage.setItem("access_token", data.access_token);
          alert("Westagram 환영합니다");
          this.props.history.push("/MainP");
        }
      });
  };

data 객체로 받아오고, key값인 MESSAGE가 SUCCESS로 일치하면, 로컬 스토리지에 저장하는 방법도 있겠으나 더욱 간단하게 생각하면 access_token이 존재하면, true면 저장하는 식을 세울 수도 있다.

if (res.access_token) {
          localStorage.setItem("access_token", res.access_token);
          alert("Westagram 환영합니다");
          this.props.history.push("/MainP");
        }


토큰이 내 localStorage에 잘 저장된 것을 볼 수 있다!


2. POSTING API

mock data로만 구현했던 데이터 받아오기를 백엔드로부터 받아와서 피드에 나타나게 했다.

기존에 mock data 로 받아온 것

componentDidMount() {
    fetch("/data/FeedData.json", {
      method: "GET",
    })
      .then((res) => res.json())
      .then((data) => {
        this.setState({
          feedLists: data,
        });
      });
  }

단순히, 로컬에 있는 파일을 가져오는 것이므로 method는 GET이 된다. 앞의 주소들도 로컬 주소이기에 생략가능하고, GET 또한 디폴트 값이므로 생략가능하다.

위에서 localStorage.setItem에 저장된 토큰들을 getItem() 메소를 이용하여 request header에 담아 보내야 한다. 어디로 보내줘야할지 백엔드에게 물어봐야하고 보통은 Authorization 이라고 생각하면 된다고 한다.

정보를 서버로 보낸 후, Backend의 data를 받아온 것

 componentDidMount() {
   fetch("http://10.58.7.14:8000/postings/post", {
	method: "POST",
	headers: {
	Authorization: localStorage.getItem("access_token"),
	},
	})
	body: JSON.stringify({
	hashtag: "#병재님이랑 통신의 날",
	image: "https://scontent-ssn1-1.cdninstagram.com/v/t51.2885-15/e35/p1080x1080/162854179_871941930325427_802243224954199745_n.jpg?tp=1&_nc_ht=scontent-ssn1-1.cdninstagram.com&_nc_cat=111&_nc_ohc=9uofJ07-RJ4AX8PHHt_&edm=AAeKFY8AAAAA&ccb=7-4&oh=6214029d35bbddeba093dc7fa4229316&oe=6091EF9A&_nc_sid=c982ba",
	content: "불코딩~~",
      //밑 생략
    )}
  }                      
 componentDidMount() {
    fetch("http://10.58.7.14:8000/postings/post", {
      method: "POST",
      headers: {
        Authorization: localStorage.getItem("access_token"),
      },
    })
      .then((res) => res.json())
      .then((res) => {
        this.setState({
          feedLists: res.result,
        });
      });
  }

현재 로그인 된 사람만이 인증이 되어 포스팅 버튼을 클릭시(나같은 경우에는 메인페이지로 자동으로 넘어갈 시 뜨는걸로 구현했다) 백엔드에서 저장했던 피드 데이터 정보들을 가져올 것이다.

데이터를 주고 받으면서 여러가지 에러들을 많이 마주하게 되었는데, 에러를 해독하는 능력이 생긴 것 같다| ᐕ)੭*⁾⁾ failed to fetch, JSON token error, key error 등, 에러를 보며 하나씩 뜯어보고 고쳐나가며 공부가 되었다.

fetch() 함수 이해하기
📎 https://www.daleseo.com/js-window-fetch/

profile
motivation⚡️

0개의 댓글