[TIL] 230713

이세령·2023년 7월 13일
0

TIL

목록 보기
55/118

로그인

처음에 isSuccess/isError로 구현했다가 처음에 동작이 제대로 안되는 것을 보고 on~로 회원가입과, 로그인 동작을 모두 수정해주었다.

const mutation = useMutation(signIn, {
    onSuccess: (data) => {
      const token = data.token; // toekn 받음
      console.log("token", data.token);
      // 쿠키 저장, 유효시간 설정
      document.cookie = `token=${token}; max-age=600`;
      // dispatch(setUser({ id: loginUser.id }));
      alert("로그인 되었습니다!");
      //   navigate("/");
      console.log("로그인", token, userId);
    },
    onError: (error) => {
      console.log("onerror", error);
      if (error.response.status === 401) {
        return alert(error.response.data.message);
      }
      return alert(error.message);
    },
  });

axios intercept

로그인 동작 구현 중, 동작을 실행할 때 마다 token인증을 하기 위해서 질문을 해보던 중, intercept로 중간에 작업을 추가해줄 수 있다는 사실을 알았다.
만료 된 채로 요청 -> 401 에러 -> 메시지 출력, token 삭제 후 login page로 이동

aut.js

const instance = axios.create({
  baseURL: `${process.env.REACT_APP_AUTAPI_URL}user`,
  headers: { "Content-Type": "application/json" },
});

요청을 보내기 전 수행해야 하는 것은 없기 때문에 응답 내보내기 전에 처리만 해준다.

오류가 발생했을 때 error처리를 401일 때 메시지를 출력해주도록 코드를 수정한다.

// 응답 내보내기 전
instance.interceptors.response.use(
  function (config) {
    return config;
  },
  function (error) {
    const msg = error.response.data.message;
    const status = error.response.status;
    console.log("응답 보내기 전", error);
    console.log(msg);
    /**
     * 만료 된 채로 요청 -> 401 에러 -> 메시지 출력, token 삭제 후 login page로 이동
     */
    if (status === 401) {
      if (msg === "토큰이 만료되었습니다. 토큰은 60분간 유지됩니다.") {
        document.cookie = "token=; expires=-1;";
        alert(`${msg} 다시 로그인 해주세요!`);
        return "expire";
      } else if (
        msg === "위조되었거나 잘못된 형식의 token입니다.(jwt malformed)"
      ) {
        document.cookie = "token=; expires=-1;";
        return "falsify";
      } else if (msg === "token value가 존재하지 않습니다.") {
        return "nonetoken";
      } else {
        return;
      }
    }

    return error;
  }
);

users.js

// 유저 인증 확인
const checkAut = async (token) => {
  const response = await aut.get("", {
    headers: {
      authorization: `Bearer ${token}`,
    },
  });
  return response.data;
};

인증 확인을 렌더링 했을 때 마다 시도해주자.

쿠키에 저장되어 있는 토큰 가져오기

const token = document.cookie.split("=")[1];

인증 동작 컴포넌트

새 컴포넌트를 넣어, 렌더링이 될 때 마다 실행하여 토큰을 인증하려고 한다.
Authorization.jsx

import React, { useEffect } from "react";
import { useMutation } from "react-query";
import { checkAut } from "../api/users";

function Authorization() {
  const token = document.cookie.split("=")[1];
  console.log("토큰있어?", token);

  const mutation = useMutation(checkAut, {
    onSuccess: () => {},
    onError: (error) => {
      console.log("autError", error);
    },
  });

  useEffect(() => {
    mutation.mutate(token);
  }, []);

  return <></>;
}

export default Authorization;

Error

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons

함수 컴포넌트나 커스텀 훅 내에서만 사용해야하는데 그렇지 않았을 때 발생하는 오류이다.

aut.js에서 useNavigate를 사용해서 발생하는 오류였기에 useNavigate를 다른 곳에 사용했다.

로그아웃

로그인 했을 때의 정보를 redux에 담아, { id: "", isLogin: false } 의 상태에 따라 로그인, 로그아웃 버튼이 나타나게 만들었다.

const navigate = useNavigate();
  const currentUser = useSelector((item) => item.currentuser);
  const [isLogin, setIsLogin] = useState(false);
  const dispatch = useDispatch();

  const logoutHandler = () => {
    document.cookie = "token=; expires=-1;";
    dispatch(logoutUser());
    setIsLogin(currentUser.isLogin);
    alert("로그아웃 되었습니다!");
    console.log(currentUser);
  };

  useEffect(() => {
    setIsLogin(currentUser.isLogin);
  }, [currentUser]);

.
.
<div>
            {!isLogin && (
              <Button onClick={() => navigate("/signin")}>LogIn</Button>
            )}
            {isLogin && <Button onClick={() => logoutHandler()}>Logout</Button>}
          </div>

새로고침 등 했을 때 redux 정보가 지워져서 토큰의 존재유무로 판별하였다.

const navigate = useNavigate();
  const token = document.cookie.split("=")[1];
  const currentUser = useSelector((item) => item.currentuser);
  const [isLogin, setIsLogin] = useState(false);
  const dispatch = useDispatch();

  const logoutHandler = () => {
    document.cookie = "token=; expires=-1;";
    dispatch(logoutUser());
    setIsLogin(currentUser.isLogin);
    alert("로그아웃 되었습니다!");
    console.log(currentUser);
  };

  useEffect(() => {
    if (token.trim()) {
      setIsLogin(true);
    } else {
      setIsLogin(false);
    }
  }, [currentUser]);

로그인 상태일 때 로그인, 회원가입 페이지 들어가지 못하게 만들기

해당 페이지에 접속했을 때, 각종 error가 아니라 온전한 로그인 상태이고 url을 비교하여 로그인/회원가입 페이지에 들어가지 못하게 막는다.
Authorization.jsx

const preventSign = () => {
    if (token) {
      alert("로그아웃 해주세요!");
      navigate("/");
    }
  };

  useEffect(() => {
    const currentUrl = window.location.href.split("/");
    const url = currentUrl[currentUrl.length - 1];
    console.log("url", url, token);
    if (url === "signin" || url === "signup") {
      preventSign();
    }

    mutation.mutate(token);
  }, []);

interceptor의 사용법과 로그인, 회원가입에서 쿠키가 어떻게 주고받는지, jwt를 언제 사용하는지 동작과정을 알 수 있었다.

profile
https://github.com/Hediar?tab=repositories

0개의 댓글