JWT 로그인 인증방식

서인·2023년 7월 21일
0
post-thumbnail

간단하게 해결했지만 너무 어렵게 생각했는지 좀 빙빙 돌려서 오래 걸렸다. 아래는 전체 코드가 아닌 해결 과정을 정리했다.

현재 코드에서는 유저 데이터만 저장이 되어 로그인이 백엔드에 연동은 되었지만, localstorage에 토큰은 저장이 되지 않는 상태였다.

import axios, { AxiosResponse } from 'axios';

import { axiosInstance } from '../axiosInstance';
import { useUser } from '../components/user/hooks/useUser';
import { User } from '../types/types';

interface UseAuth {
  signin: (email: string, password: string) => Promise<void>;
  signup: (email: string, password: string, nickname: string) => Promise<void>;
  signout: () => void;
}

type UserResponse = { user: User };
type ErrorResponse = { message: string };
type AuthResponseType = UserResponse | ErrorResponse;

export function useAuth(): UseAuth {
  const SERVER_ERROR = 'There was an error contacting the server.';
  const { clearUser, updateUser } = useUser();

  async function authServerCall(
    urlEndpoint: string,
    email: string,
    password: string,
    nickname?: string,
  ): Promise<void> {
    try {
      const { data, status }: AxiosResponse<AuthResponseType> =
        await axiosInstance({
          url: urlEndpoint,
          method: 'POST',
          data: { email, password, nickname },
          headers: { 'Content-Type': 'application/json' },
        });
      if (status === 201) {
        // eslint-disable-next-line no-alert
        alert(`status code : ${status}! 회원가입 성공`);
        return;
      }
    } catch (errorResponse) {
      const status =
        axios.isAxiosError(errorResponse) && errorResponse?.response?.status
          ? errorResponse?.response?.status
          : SERVER_ERROR;
      status === 409
        ? // eslint-disable-next-line no-alert
          alert(`status code : ${status}! already a member!`)
        : // eslint-disable-next-line no-alert
          alert(`status code : ${status}!`);
    }
  }
  type accessToken = string;
  async function authLoginServerCall(
    urlEndpoint: string,
    email: string,
    password: string,
  ): Promise<void> {
    try {
      const { data, status }: AxiosResponse<AuthResponseType, accessToken> =
        await axiosInstance({
          url: urlEndpoint,
          method: 'POST',
          data: { email, password },
          headers: { 'Content-Type': 'application/json' },
        });
      if (status === 201 || status === 200) {
        // eslint-disable-next-line no-alert
        alert(`status code : ${status}! 로그인 성공`);
        if ('user' in data) {
          // update stored user data
          updateUser(data.user);
        }
        // eslint-disable-next-line no-console
        console.log('data', data);
        // API 요청하는 콜마다 헤더에 accessToken 담아 보내도록 설정
        // axios.defaults.headers.common[
        //   'Authorization'
        // ] = `Bearer ${accessToken}`;

        // const user: User = { accessToken: token };
        // setStoredUser({ data });
        // setStoredUser(user);
      }

      // if ('user' in data && 'accessToken' in data.user) {
      if ('user' in data && 'accessToken' in data.user) {
        // eslint-disable-next-line no-console
        console.log(data);
        // update stored user data
        updateUser(data.user);
      }
    } catch (errorResponse) {
      const status =
        axios.isAxiosError(errorResponse) && errorResponse?.response?.status
          ? errorResponse?.response?.status
          : SERVER_ERROR;
      status === 409
        ? // eslint-disable-next-line no-alert
          alert(`status code : ${status}! already a member!`)
        : // eslint-disable-next-line no-alert
          alert(`status code : ${status}!`);
    }
  }

  async function signin(email: string, password: string): Promise<void> {
    authLoginServerCall('/members/signin', email, password);
    // authServerCall('/members/signin', email, password);
  }
  async function signup(
    email: string,
    password: string,
    nickname: string,
  ): Promise<void> {
    authServerCall('/members/signup', email, password, nickname);
  }

  function signout(): void {
    // clear user from stored user data
    clearUser();
    // eslint-disable-next-line no-alert
    alert(`logged out!`);
  }

  return {
    signin,
    signup,
    signout,
  };
}

문제가 되는 부분은 이거였다. 팀원 분이 작성하신 코드인데, 타입 문제도 많고 무엇보다 안 돌아간다. jwt 인증방식이고 뭐고 잘 몰랐던 상태에서 보니 나는 이게 타입 문제만 해결되면 맞는 코드이지 않을까? 싶어서 좀 파봤지만 이게 어떤 식으로 돌아가는지 도저히 이해도 안 되고 에러도 해결이 안됐다. 그래서 localstorage에 토큰을 어떻게 저장하고 그걸 로그인 할 때만 빼올 수 있을까? 고민을 많이했다.

 // axios.defaults.headers.common[
        //   'Authorization'
        // ] = `Bearer ${accessToken}`;

        // const user: User = { accessToken: token };
        // setStoredUser({ data });
        // setStoredUser(user);
      }

토큰 관련해서 어떻게 처리해야하는지 받은 슬랙

처음에는 localstorage.setItem()을 사용해서 로그인 시에 토큰을 가져오려고 시도했다.

 localStorage.setItem('accessToken', data);

근데 이렇게하면 타입이 안 맞는다 ㅎㅎ..

localStorage.setItem('accessToken', JSON.stringify(data));
// eslint-disable-next-line no-console
console.log(localStorage);

JSON.stringify를 사용해서 넣어줬다. 그리고 콘솔 창을 확인했는데 아무것도 안 떴다 ^^ 지금 생각해보면 당연하다 아무것도 안 했는데 어떻게 받아옴?

지금 함수가 서버콜이랑 서버로그인콜로 나뉘어져 있는데, 서버 콜쪽 header에 authorization을 추가해줬다.

Promise<void> {
    try {
      const { data, status }: AxiosResponse<AuthResponseType> =
        await axiosInstance({
          url: urlEndpoint,
          method: 'POST',
          data: { email, password, nickname },
          headers: { 'Content-Type': 'application/json'
          Authorization: `Bearer ${localStorage.getItem('accessToken')}`,},
        });

이렇게 코드를 작성하면 회원가입을 완료했을 때 localstorage에 token을 생성하고, 로그인할 때 생성했던 토큰을 return한다.

그냥 간단한 구현인데 TIL써야하니까 썼다

profile
> ㅁ <

0개의 댓글