prosource

리액트 라우터에서 페이지 새로 고침 시에도 로그 상태를 유지하는 방법은 무엇입니까?

probook 2023. 3. 29. 21:36
반응형

리액트 라우터에서 페이지 새로 고침 시에도 로그 상태를 유지하는 방법은 무엇입니까?

리액트, 리액트 라우터, 리덕스로 웹사이트를 만들고 있습니다.많은 루트(페이지)에서는 사용자가 로그인해야 합니다.사용자가 다음과 같이 로그인하지 않으면 로그인 페이지로 리디렉션할 수 있습니다.

function requireAuth(nextState, replace) {
    let loggedIn = store.getState().AppReducer.UserReducer.loggedIn;

    if(!loggedIn) {
        replace({
            pathname: '/login',
            state: {
                nextpathname: nextState.location.pathname
            }
        });
    }
}

ReactDOM.render(
    <Provider store={store}>
        <Router history={history}>
            <Route path="/" component={App}>
                <IndexRoute component={Index} />
                <Route path="login" component={Login} />
                <Route path="register" component={Register} />
                <Route path="dashboard" component={Graph} onEnter={requireAuth}>
                    ... some other route requires logged in ...
                </Route>
            </Route>
        </Router>
    </Provider>,
    document.getElementById('entry')
);

코드를 참조하십시오. 사용자가 로그인하지 않은 경우 onEnter 후크를 사용하여 '/login' 경로로 리디렉션했습니다.사용자가 로그인하고 있는지 확인하기 위한 데이터는 스토어에 있으며 사용자가 로그인한 후 업데이트됩니다.

정상적으로 동작하고 있습니다만, 페이지를 리프레시 하면, 스토어가 리셋 되어, 유저가 다시 로그인하지 않는 것이 문제입니다.

Redux 저장소는 메모리 스토리지일 뿐이므로 페이지를 새로 고치면 저장소의 모든 데이터가 손실됩니다.

새로 고침 시마다 서버 세션을 확인하는 것은 작동하지만 요청이 너무 많을 수 있으므로 이는 잘못된 생각인 것 같습니다.

로그인한 상태 데이터를 localStorage에 저장하면 효과가 있을 수 있지만, 이 경우 세션이 만료되었거나 존재하지 않기 때문에 거부된 요청에 실패한 모든 AJAX 호출을 확인해야 합니다. 그것도 잘못된 생각인 것 같습니다.

이 문제를 좀 더 간단하게 해결할 수 있는 방법이 없을까요?제 웹사이트는 많은 사용자를 처리해야 하기 때문에 XHR 통화를 최대한 줄이고 싶습니다.

어떤 조언이라도 감사합니다.

또 하나의 방법은 각 루트에 필요한 JSON Web 토큰(JWT)localStorage사용하여 JWT를 확인하는 것입니다.

TL;DR

  • 프런트 엔드에는 서버 인증에 따라 서버에 JWT를 문의하는 사인인과 사인업루트가 있습니다적절한 JWT를 통과하면 상태 속성을 true로 설정합니다.사용자가 이 상태를 false로 설정할 수 있는 사인아웃루트를 설정할 수 있습니다.

  • 경로를 포함하는 index.js는 렌더링 전에 로컬 스토리지를 확인할 수 있으므로 새로 고침 시 상태를 손실하면서도 보안을 유지해야 하는 문제를 방지할 수 있습니다.

  • 응용 프로그램에서 인증이 필요한 모든 경로는 Composed Component를 통해 렌더링되며 서버 API 인증을 위해 헤더에 JWT가 있어야 합니다.

이 설정에는 약간의 시간이 걸리지만, '합리적인' 애플리케이션 보안을 유지할 수 있습니다.


문제를 해결하려면:

루트 전에 로컬 스토리지를 확인합니다.index.js다음과 같이 파일을 작성하고 필요에 따라 상태를 인증 완료로 업데이트합니다.

어플리케이션은 API가 JWT에 의해 보호되므로 갱신 문제를 해결하고 서버와 데이터에 대한 안전한 링크를 유지할 수 있습니다.

따라서 루트에는 다음과 같은 것이 있습니다.

index.displaces를 표시합니다.

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
import reduxThunk from 'redux-thunk';
import { AUTHENTICATE_THE_USER } from './actions/types';
import RequireAuth from './components/auth/require_auth';
import reducers from './reducers';

/* ...import necessary components */

const createStoreWithMiddleware = compose(applyMiddleware(reduxThunk))(createStore);

const store = createStoreWithMiddleware(reducers);

/* ... */

// Check for token and update application state if required
const token = localStorage.getItem('token');
if (token) {
    store.dispatch({ type: AUTHENTICATE_THE_USER });
}

/* ... */

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={App}>
        <IndexRoute component={Index} />
        <Route path="login" component={Login} />
        <Route path="register" component={Register} />
        <Route path="dashboard" component={RequireAuth(Graph)} />
        <Route path="isauthenticated" component={RequireAuth(IsAuthenticated)} />
        ... some other route requires logged in ...
      </Route>
    </Router>
  </Provider>
  , document.getElementById('entry'));

RequiredAuth컴포넌트입니다.Graph그리고.IsAuthenticated(적절하게 명명된 컴포넌트의 수에는 제한이 없습니다)는state.authenticated진실되게.

이 경우 컴포넌트Graph그리고.IsAuthenticated렌더링된 것은state.authenticated정말이에요.그렇지 않으면 기본적으로 루트 루트로 돌아갑니다.


그런 다음 모든 경로가 렌더링되는 다음과 같은 구성 요소를 작성할 수 있습니다.렌더링 전에 사용자가 인증되었는지(부울) 여부를 사용자가 보유하고 있는 상태가 true인지 확인합니다.

require_auth.syslog

import React, { Component } from 'react';
import { connect } from 'react-redux';

export default function (ComposedComponent) {

  // If user not authenticated render out to root

  class Authentication extends Component {
    static contextTypes = {
      router: React.PropTypes.object
    };

    componentWillMount() {
      if (!this.props.authenticated) {
        this.context.router.push('/');
      }
    }

    componentWillUpdate(nextProps) {
      if (!nextProps.authenticated) {
        this.context.router.push('/');
      }
    }

    render() {
      return <ComposedComponent {...this.props} />;
    }
  }

  function mapStateToProps(state) {
    return { authenticated: state.authenticated };
  }

  return connect(mapStateToProps)(Authentication);
}

서명/사인 측에서는 JWT를 저장하고 action-creator -> redux 스토어를 통해 인증되도록 상태를 설정하는 액션을 작성할 수 있습니다.예에서는 Axios를 사용하여 비동기 HTTP 요청 응답 사이클을 실행합니다.

export function signinUser({ email, password }) {

  // Note using the npm package 'redux-thunk'
  // giving direct access to the dispatch method
  return function (dispatch) {

    // Submit email and password to server
    axios.post(`${API_URL}/signin`, { email, password })
      .then(response => {
        // If request is good update state - user is authenticated
        dispatch({ type: AUTHENTICATE_THE_USER });

        // - Save the JWT in localStorage
        localStorage.setItem('token', response.data.token);

        // - redirect to the route '/isauthenticated'
        browserHistory.push('/isauthenticated');
      })
      .catch(() => {
        // If request is bad show an error to the user
        dispatch(authenticationError('Incorrect email or password!'));
      });
  };
} 

물론 스토어(이 경우 Redux)와 액션 크리에이터도 설정해야 합니다.

진정한 보안은 백엔드에서 이루어집니다.이를 위해 localStorage를 사용하여 JWT를 프런트엔드에 유지하고 중요한/보호 정보를 가진 API 호출에 헤더로 전달합니다.

서버 API에서 사용자용 JWT를 작성하고 해석하는 것도 하나의 단계입니다.나는 여권이 유효하다는 것을 알았다.

로그인 상태 및 만료 날짜가 있는 sessionStorage를 사용하지 않는 이유는 무엇입니까?sessionStorage 상태를 확인하려면 코드를 더 작성해야 하지만, XHR 호출을 전송하지 않도록 하는 유일한 방법이라고 생각합니다.

언급URL : https://stackoverflow.com/questions/39097440/on-react-router-how-to-stay-logged-in-state-even-page-refresh

반응형