2016-08-23 10 views
19

나는 Redux가있는 React and React Router로 웹 사이트를 만들고있다. 경로 (페이지)의 제비가 로그인이 필요합니다 사용자가이 같은 로그인하지 않은 경우 내가 로그인 리디렉션 할 수 있습니다.React Router에서 로그인 상태를 유지하는 방법에도 페이지를 새로 고침 하시겠습니까?

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 사용 로그인하지 않은 사용자를 확인하는 데이터는 상점에 있으며 사용자가 로그인하면 업데이트됩니다.

완벽하게 작동하지만 페이지를 새로 고칠 때 저장소가 재설정되고 사용자가 아닌 경우 문제가 있습니다. 다시 상태로 로그인했습니다.

Redux 저장소는 메모리 저장소이므로 refesh 페이지에서 모든 데이터가 손실되므로이 문제가 발생합니다.

새로 고침 할 때마다 서버 세션을 확인해 볼 수는 있지만 너무 많은 요청 일 수 있으므로 좋지 않은 것처럼 보입니다.

localStorage에 상태 데이터를 저장하는 것이 효과적 일 수도 있지만,이 경우 세션이 만료되었거나 아무것도 존재하지 않으므로 모든 AJAX 호출이 거부 된 요청을 확인해야하며 나쁜 아이디어로 보입니다.

이 문제를보다 명확하게 해결할 수있는 방법이 있습니까? 내 웹 사이트는 많은 사람들을 사용할 것이므로 가능한 한 XHR 전화를 줄이려고합니다.

모든 조언은 매우 감사하겠습니다.

답변

24

또 다른 방법은 각 경로에 필요한 JSON Web Tokens (JWT)을 사용하고 JWT를 확인하려면 localStorage을 사용하는 것입니다.

TL, 프론트 엔드에 DR

  • 당신은 서버의 인증에 따라 JWT에 대한 귀하의 서버를 조회하는 로그인 절차 및 가입 경로를 가지고있다. 이 적절한 JWT를 통과하면 상태 속성을 으로 설정합니다. 사용자가이 상태를 false로 설정할 수있는 로그 아웃 경로가있을 수 있습니다.

  • 경로가 포함 된 index.js는 렌더링 전에 로컬 스토리지 을 검사 할 수 있으므로 새로 고침시 상태는 손실되지만 보안은 유지하면서 문제를 해결할 수 있습니다. 응용 프로그램에서 인증을 요구

  • 모든 노선 합성 구성 요소를 통해 렌더링, 서버 API에 대한 권한 부여를 위해 헤더에 가진 JWT를의 필요성로 고정된다.

이렇게 설정하는 데는 약간의 시간이 걸리지 만 응용 프로그램을 '합리적으로'안전하게 만듭니다.필요한 경우 인증에 상태를 업데이트, 아래 그림과 같이

index.js 파일의 경로 전에 로컬 스토리지를 확인하십시오


가 문제를 해결합니다.

응용 프로그램은 새로 고침 문제를 해결할 API가 JWT에 의해 보안되고 사용자의 서버 및 데이터에 대한 보안 연결을 유지한다는 점에서 보안을 유지합니다.

따라서 경로에서이 같은 것이다 : GraphIsAuthenticated이 (적절라는 이름의 구성 요소의 숫자가 될 수 있습니다) 동안
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> 
    , .getElementById('entry')); 

RequiredAuth가 합성 요소입니다

하는 index.js

state.authenticated이 참이어야합니다.

구성 요소 (이 경우 state.authenticated이 참일 경우 GraphIsAuthenticated이 렌더링 됨). 그렇지 않은 경우 기본값은 루트 경로로 돌아갑니다.


그런 다음 모든 경로가 렌더링되는 이와 같이 구성된 구성 요소를 작성할 수 있습니다. 렌더링 전에 사용자가 인증되었는지 여부 (부울 값)가 ​​true인지 여부를 확인합니다.

require_auth.js 당신이 JWT를 저장하고 작업 제작자를 통해 인증 할 수있는 상태 설정 작업 만들 수 있습니다 가입/로그인의 측면에서

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); 
} 

-> REDUX 저장소를 . 이 예제 makes use of 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!')); 
     }); 
    }; 
} 

은 또한 (이 경우 돌아 오는) 저장 및 과정의 행동 작성자를 설정해야합니다.

'실제'보안은 백 엔드에서 제공됩니다. 이렇게하려면 localStorage를 사용하여 JWT를 프런트 엔드에 유지하고 민감한/보호 된 정보가있는 API 호출에 헤더에서 전달합니다.

서버 API에서 사용자에 대한 JWT를 만들고 구문 분석하는 것은 또 다른 단계입니다. I have found passport to be effective.

+0

예제에서 IsAuthenticated는 ComposedComponent입니까? – klode

+0

'RequiredAuth'는 합성 된 구성 요소이고'IsAuthenticated'는 'state.authenticated'가 참이어야하는 적절하게 이름 지정된 구성 요소의 수입니다. 답변을 업데이트했습니다. – alexi2

+0

감사합니다. 새 편집이 더 명확합니다. – klode

1

로그인 상태 및 만료일과 함께 sessionStorage를 사용하지 않는 이유는 무엇입니까? sessionStorage 상태를 검사하기 위해 더 많은 코드를 작성해야하지만, 이것이 내 의견으로는 XHR 호출을 보내지 않도록 저장할 수있는 유일한 방법입니다.

관련 문제