6-6. 새로고침 할 시 로그인 유지하기

로그인을 한다고해서, 기본적으론 앱 내에서 자동으로 로그인 상태가 유지되지 않습니다. 브라우저를 새로고침하면 스토어 값이 초기화되기 때문인데요, 그렇기 때문에 페이지에 들어왔을 때 유저정보를 다시 넣어주는 작업이 필요합니다.

이 작업은 다음 과정을 거쳐서 구현됩니다.

  • App 이 불러와졌을 때 로컬스토리지에 있던 유저 정보 사용
  • 서버에 현재 로그인 상태 재검증
  • 서버가 응답한 로그인 정보로 업데이트
  • 만약에 토큰이 만료되었을 시에는, 재로그인 요청

src/App.js

import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import { Home, Auth } from 'pages';
import HeaderContainer from 'containers/Base/HeaderContainer';

import storage from 'lib/storage';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import * as userActions from 'redux/modules/user';

class App extends Component {


    initializeUserInfo = async () => {
        const loggedInfo = storage.get('loggedInfo'); // 로그인 정보를 로컬스토리지에서 가져옵니다.
        if(!loggedInfo) return; // 로그인 정보가 없다면 여기서 멈춥니다.

        const { UserActions } = this.props;
        UserActions.setLoggedInfo(loggedInfo);
        try {
            await UserActions.checkStatus();
        } catch (e) {
            storage.remove('loggedInfo');
            window.location.href = '/auth/login?expired';
        }
    }

    componentDidMount() {
        this.initializeUserInfo();
    }

    render() {
        return (
            <div>
                <HeaderContainer/>
                <Route exact path="/" component={Home}/>
                <Route path="/auth" component={Auth}/>
            </div>
        );
    }
}

export default connect(
    null,
    (dispatch) => ({
        UserActions: bindActionCreators(userActions, dispatch)
    })
)(App);

코드를 저장하고, 페이지를 새로고침 한 다음에, 리덕스 개발자 도구를 통해 상태를 조회해보세요.

로그아웃 임시구현

우리는 나중에 다음과 같은 유저 메뉴를 구현하게 됩니다.

이 유저메뉴를 구현하기 전에, 미리 임시적으로 로그아웃 기능을 구현해보도록 하겠습니다.

src/containers/Base/HeaderContainer.js

import React, { Component } from 'react';
import Header, { LoginButton } from 'components/Base/Header';
import { connect } from 'react-redux';
import * as userActions from 'redux/modules/user';
import { bindActionCreators } from 'redux';
import storage from 'lib/storage';



class HeaderContainer extends Component {

    handleLogout = async () => {
        const { UserActions } = this.props;
        try {
            await UserActions.logout();
        } catch (e) {
            console.log(e);
        }

        storage.remove('loggedInfo');
        window.location.href = '/'; // 홈페이지로 새로고침
    }

    render() {
        const { visible, user } = this.props;
        if(!visible) return null;



        return (
            <Header>
                { user.get('logged') 
                    ? (<div>
                        {user.getIn(['loggedInfo', 'username'])} <div onClick={this.handleLogout}>(로그아웃)</div>
                    </div> )
                    : <LoginButton/> 
                }
            </Header>
        );
    }
}

export default connect(
    (state) => ({
        visible: state.base.getIn(['header', 'visible']),
        user: state.user
    }),
    (dispatch) => ({
        UserActions: bindActionCreators(userActions, dispatch)
    })
)(HeaderContainer);

로그아웃을 할 때에는, 로그아웃 요청을 하고, 로컬스토리지도 비워주어야 합니다.

로그인 만료시 에러메시지 띄우기

우리가 App 컴포넌트를 수정 할 때, 로컬스토리지에는 로그인 정보가 있는데 서버측에서는 로그인 상태가 아니라고 할 때는 /auth/login?expired 경로로 이동하게 했었습니다.

이번엔, 로그인 페이지에서 expired 파라미터가 존재하면 에러메시지를 띄워보겠습니다.

쿼리를 파싱하기 위해서 query-string 을 설치하세요.

$ yarn add query-string

그리고, Login 컴포넌트의 componentDidMount 를 다음과 같이 수정하세요.

src/containers/Auth/Login.js

(...)
import queryString from 'query-string';

class Login extends Component {

    componentDidMount() {
        const { location } = this.props;
        const query = queryString.parse(location.search);

        if(query.expired !== undefined) {
            this.setError('세션에 만료되었습니다. 다시 로그인하세요.')
        }
    }

    (...)

코드를 다 작성하셨다면 http://localhost:3000/auth/login?expired 링크로 이동해보세요.

메시지가 잘 떴나요?

results matching ""

    No results matching ""