node.js

내 로그인 정보 매번 불러오기

Heoky 2022. 1. 18. 23:10

로그인 이후 새로고침을 하게 되면 로그인이 풀리는 문제가 발생한다. 어떻게 해결해야 될까?


1. 프론트에서 페이지가 새로고침이 될때마다(useEffect) 로그인 된 user의 정보를 매번 불러준다.

2. 백엔드 서버(user router)에서는 get을 통해 로그인 된 user의 정보를 매번 불러온다.
- passport 전략에 의해 로그인, req.user의 정보가 있으면 user의 정보를 매번 반환하고
- 없다면 null을 보내면 된다.


1. user 정보를 가져올 router를 만들어준다. (get)

// routes/user.js

const router = require('express').Router();
const { User } = require('../models');

// GET /user
router.get('/', async (req, res, next) => {
  try {
    if (req.user) {
      const user = await User.findOne({
        where: {
          id: req.user.id,
        },
      });
      res.status(200).json(user);
    } else {
      res.status(200).json(null);
    }
  } catch (err) {
    console.error(err);
    next(err);
  }
});

passport의 로그인 전략에 의해 로그인이 성공적으로 이루어졌다면, req.user 안에 user의 정보가 담겨져있다.
get 요청이 왔을 때 model의 User에서 로그인 된 상태의 req.user.id를 찾아 사용자의 정보를 계속 유지하게끔 정보를 전달해준다.

2. 프론트에서(next.js와 redux, redux-saga 사용 기준) 화면이 렌더링 될 때마다 로그인된 user의 정보를 설정한 state에 계속
담아준다.

import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';

import { LOAD_MY_INFO_REQUEST } from '../reducers/user';

const Home = () => {
  const dispatch = useDispatch();
  
  useEffect(() => {
    dispatch({
      type: LOAD_MY_INFO_REQUEST, // 화면이 렌더링 될 때마다 user의 정보를 요청
    });
  }, []);
  
  return (
  	...
  )
  }

한 페이지의 예를 든 것이고 이렇게 각각의 페이지마다 렌더링 시 user의 정보를 매번 요청해주면 된다.

sagas/user.js

function loadMyInfoAPI() {
  return axios.get('/user');
}

function* loadMyInfo(action) {
  try {
    // api 통신할때는 call
    const result = yield call(loadMyInfoAPI, action.data);
    // yield delay(1000);
    yield put({
      type: LOAD_MY_INFO_SUCCESS,
      data: result.data,
    });
  } catch (err) {
    yield put({
      type: LOAD_MY_INFO_FAILURE,
      error: err.response.data,
    });
  }
}

reducers/user.js

export const initialState = {
  loadMyInfoLoading: false,
  loadMyInfoDone: false,
  loadMyInfoError: null,
  me: null,
};

export const LOAD_MY_INFO_REQUEST = 'LOAD_MY_INFO_REQUEST';
export const LOAD_MY_INFO_SUCCESS = 'LOAD_MY_INFO_SUCCESS';
export const LOAD_MY_INFO_FAILURE = 'LOAD_MY_INFO_FAILURE';

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case LOAD_MY_INFO_REQUEST:
      return {
        ...state,
        loadMyInfoLoading: true,
        loadMyInfoDone: false,
        loadMyInfoError: null,
      };
    case LOAD_MY_INFO_SUCCESS:
      return {
        ...state,
        loadMyInfoLoading: false,
        loadMyInfoDone: true,
        me: action.data,
      };
    case LOAD_MY_INFO_FAILURE:
      return {
        ...state,
        loadMyInfoLoading: false,
        loadMyInfoError: action.error,
      };
    default:
      return state;
  }
};

export default reducer;