기능 구현 리액트 - 로그인한 사용자의 로그인 여부 확인.

이유승·2023년 7월 19일
0

기능 구현

목록 보기
8/21
post-custom-banner

간단한 수준의 회원기능을 구현하는 것은 그렇게 어려운 일이 아니다. 내가 프로젝트에서 회원기능을 구현한 다음에 가장 고민했던 문제는 도대체 어떻게 로그인한 사용자의 데이터를 관리해야하는지, 로그인 상태를 확인하고 유지하는 방법을 구현해야하는지에 대한 것이었다.



1. onAuthStateChanged.

파이어베이스는 사용자의 인증 상태를 확인하는 함수를 제공하고 있다. 이 함수가 호출되었을 때, 파이어베이스 서버에 접속해 있는 사용자가 있는지 그리고 정상적인 인증 상태를 가지고 있는지 확인하는 것이다.

// 유저 로그인 여부 확인.
const IsLoginCheck = () => {
    return (dispatch, getState) => {
        dispatch({ type: 'STATE_INIT' });
        dispatch({ type: 'LOADING' });

        onAuthStateChanged(appAuth, (user) => {
            if (!user) {
                console.log('사용자 인증 정보가 존재하지 않음.');
                dispatch({ type: 'COMPLETE' });
                dispatch({ type: 'LOG_OUT' });
            }
            else {
                const loginUserData = {
                    email: user.email,
                    displayName: user.displayName,
                    emailVerified: user.emailVerified,
                    isAnonymous: user.isAnonymous,
                };
                dispatch({ type: 'COMPLETE' });
                dispatch({ type: 'LOG_IN_SUCCESS', payload: loginUserData });
            }

            // console.log('현재 유저 정보');
            // console.log(user);
        })
    };
};

함수의 사용 방법은 간단하다. onAuthStateChanged 함수가 호출되었을 때 파이어베이스 인증객체를 통해 사용자의 인증 상태를 확인하고 정상일 경우에는 user 객체를 반환하는데, 이를 통해서 사용자의 인증 상태를 확인할 수 있다.

인증 결과 문제가 없다면, user 객체에서 제공되는 데이터를 Redux Store에 저장하고 그렇지 않으면 로그아웃 함수를 호출하여 파이어베이스 시스템에 인증된 유저를 제거한다.

const getUserState = useSelector((state) => state.user);

useEffect(() => {
  console.log('로그인 상태 확인.');
  dispatch(IsLoginCheck());
  // eslint-disable-next-line
}, []);

그리고 사용자의 인증 상태를 확인해야하는 컴포넌트에 위와 같이 기능을 구현하면 된다.

코드 평가.

평가 방법, 개인적인 코드 리뷰 및 Chat GPT 사용.

-> 보안 처리 미흡. 사용자 인증 정보와 관련된 데이터를 너무 허술하게 다루고 있음. 파이어베이스 콘솔 등에서 보안 규칙과 접근 제어를 설정하여 액세스를 제한하는 것을 추천.

-> 에러 처리가 없음. 나중에 코드를 리뷰하고 깨달은 것인데, 에러에 대한 처리를 아예 까먹고 작성하지 않았었다.



2. 불안하다..

일단 구현은 해봤는데 무언가 모자라보인다. 아무리 생각해도 기능이 허술하다고 생각된다.

  • Chat GPT의 추천 1.
    어디다가 물어볼 곳도 마땅찮아서, Chat GPT의 힘을 빌려보았다. 내가 작성한 코드를 보고 평가해보고 수정할 점을 지적해달라고 했더니, Chat GPT는 다음과 같은 방법을 제시해주었다.

앱 시작 시 사용: 주로 앱이 시작될 때 (예: index.js에서) IsLoginCheck 함수를 호출하여 사용자의 로그인 상태를 확인하고 애플리케이션의 초기 상태를 설정하는 것이 좋습니다.

// index.js 또는 앱 시작점 파일

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
import { IsLoginCheck } from './path/to/IsLoginCheck';

const store = createStore(rootReducer, applyMiddleware(thunk));

// 앱 시작 전에 사용자 로그인 상태를 확인하여 초기화
store.dispatch(IsLoginCheck());

ReactDOM.render(
  <Provider store={store}>
    {/* ... */}
  </Provider>,
  document.getElementById('root')
);

그리고 따로 인증이 필요한 부분에 대해서는 아래와 같이 하는게 좋을 것 같다고 답하였다.

Redux 액션 및 리듀서: IsLoginCheck 함수에서 발생시킨 액션들은 Redux 리듀서에서 처리되어야 합니다. 예를 들어, 'LOG_OUT' 액션은 로그아웃 상태로 상태를 업데이트하고, 'LOG_IN_SUCCESS' 액션은 로그인한 사용자 정보를 저장하는 식으로 처리할 수 있습니다.

// reducers.js 파일

const initialState = {
  loading: false,
  loggedIn: false,
  user: null,
  // ...기타 상태...
};

const rootReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'STATE_INIT':
      return { ...state, loading: true };
    case 'LOADING':
      return { ...state, loading: true };
    case 'COMPLETE':
      return { ...state, loading: false };
    case 'LOG_OUT':
      return { ...state, loggedIn: false, user: null };
    case 'LOG_IN_SUCCESS':
      return { ...state, loggedIn: true, user: action.payload };
    // ...기타 액션들에 대한 상태 업데이트...
    default:
      return state;
  }
};

export default rootReducer;

컴포넌트에서 사용: 애플리케이션의 컴포넌트에서 Redux 스토어의 상태를 구독하여 로그인 상태에 따라 UI를 조정할 수 있습니다.

import React from 'react';
import { useSelector } from 'react-redux';

const App = () => {
  const loggedIn = useSelector((state) => state.loggedIn);
  const user = useSelector((state) => state.user);

  return (
    <div>
      {loggedIn ? (
        <div>
          <p>{user.displayName}</p>
          {/* 로그인된 사용자에게 보여줄 컴포넌트들 */}
        </div>
      ) : (
        <div>
          {/* 로그인되지 않은 사용자에게 보여줄 컴포넌트들 */}
        </div>
      )}
    </div>
  );
};

앱 시작 시 사용 부분을 제외하면 내가 구현했던 방법 그대로인데, 나중에 한번 확인해봐야겠다.

profile
프론트엔드 개발자를 준비하고 있습니다.
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 7월 19일

너무 잘 읽었습니다, 많은 것을 배웠습니다.

답글 달기