2017-12-10 18 views
0

frontendの部分を設計中です。ここに私ですRouter
/はログインページです。それはlocalStorageの横のtokenをチェックします。そして、それはstateルータのコンポーネント状態を別のルータコンポーネントに渡す方法

/select-teamsisAuthenticated機能ページで、LETのユーザーがそれを使用する前に、それは最初tokenを検証する必要があります。
質問は次のとおりです。
queryAPIsの前に毎回tokenをリフレッシュする必要がありますか?
2. tokenのチェックを伴うcomponentWillMountの実装間で、VSは状態を渡すたびに機能します。どちらがベストプラクティスですか? IMOはlocalStorageを読むたびにアプリの速度が低下する可能性があります。しかし、私にとっては簡単ですが、そうではありません。DRY
3. RouteからRouteの間でisAuthenticatedの状態を渡したいとします。どうやってやるの?ここで

import React from 'react'; 
import ReactDOM from 'react-dom'; 
import './index.css'; 
import registerServiceWorker from './registerServiceWorker'; 
import {Provider} from 'react-redux'; 
import {applyMiddleware, createStore} from 'redux'; 
import {BrowserRouter, Route, Switch} from 'react-router-dom'; 
import promise from 'redux-promise'; 
import LoginPage from "./components/loginPage"; 
import reducers from './reducers/index'; 
import SelectTeam from './components/select_teams'; 

const createStoreWithMiddleware = applyMiddleware(promise)(createStore); 

ReactDOM.render(
    <Provider store={createStoreWithMiddleware(reducers)}> 
    <BrowserRouter> 
     <div> 
     <Switch> 
      <Route path="/select-teams" component={SelectTeam}/> 
      <Route path="/" component={LoginPage}/> 
     </Switch> 
     </div> 
    </BrowserRouter> 
    </Provider> 
    , document.getElementById('root')); 
registerServiceWorker(); 

index.js

はので、あなたは、トークンがlocalstore /別のストレージ上にある場合はアプリが確認する必要があり反応し、トークンが有効であれば、あなたのバックエンドが検証しなければならない私の Component

import React, {Component} from 'react'; 
import {connect} from 'react-redux'; 
import login_image from '../images/login_image.png'; 
import {Field, reduxForm} from 'redux-form'; 
import {getTokenAuth, refreshToken} from "../actions"; 
import ErrorMessage from './errorMessage'; 

class LoginPage extends Component { 
    //1. Verify user token. If token is good. 
    //1.1 Do refresh token and 
    //1.2 Then put him to `select-teams` page 
    //1.3 Finally set isAuthenticated: true 

    //2. If token is not good. Let user login again. 
    //By setting the isAuthenticated: false 
    constructor(props) { 
    super(props); 
    const token = localStorage.getItem('token'); 
    const isAuthenticated = !((token === undefined) | (token === null)); 
    this.state = { 
     token: localStorage.getItem('token'), 
     isAuthenticated, 
     message: null, 
     statusCode: null 
    }; 
    } 

    componentWillMount() { 
    console.log('Enter componentWillMount'); 
    const token = this.state.token; 
    if (token === undefined || token === null) 
     this.setState((prevState) => { 
     { 
      isAuthenticated: false 
     } 
     }); 
    else { 
     console.log('componentWillMount token is exist'); 
     //Refresh the token. Let backend verify it 
     //Outcome is 1. It is expired and unable to refresh 
     //Or 2. It is refreshed 
     this.props.refreshToken(token, (res) => { 
     console.log(res.status); 
     if (res.status === 200) { 
      //Receive new token 
      localStorage.setItem('token', res.data.token); 
      this.setState((prevState) => { 
      return Object.assign(prevState, { 
       isAuthenticated: true, 
       statusCode: res.status, 
       message: res.statusText 
      }); 
      }); 
      this.props.history.push('/select-teams'); 
     } else { 
      //Token is expired and can not be able to refresh again. Force user to do login again by remove his token 
      localStorage.removeItem('token'); 
      this.setState((prevState) => { 
      return Object.assign(prevState, { 
       isAuthenticated: false, 
       statusCode: res.status, 
       message: res.data.non_field_errors 
      }); 
      }); 
     } 
     }) 
    } 
    } 

    renderField(field) { 
    const {meta: {touched, error}} = field; 
    const className = `'form-group' ${touched && error ? 'has-danger' : ''}`; 

    return (
     <div className={className}> 
     <label>{field.label}</label> 
     <input 
      className="form-control" 
      type={field.type} 
      placeholder={field.placeholder} 
      {...field.input} 
     /> 
     <div className="text-help"> 
      {touched ? error : ''} 
     </div> 
     </div> 
    ); 
    } 


    onSubmit(values) { 
    console.log(values); 
    this.props.getTokenAuth(values, (res) => { 
     console.log(res.status); 
     if (res.status === 200) { 
     localStorage.setItem('token', res.data.token); 
     this.setState((prevState) => { 
      return Object.assign(prevState, { 
      isAuthenticated: true, 
      statusCode: res.status, 
      message: res.statusText 
      }); 
     }); 
     this.props.history.push('/select-teams'); 
     } else { 
     localStorage.removeItem('token'); 
     this.setState((prevState) => { 
      return Object.assign(prevState, { 
      isAuthenticated: false, 
      statusCode: res.status, 
      message: res.data.non_field_errors 
      }); 
     }); 
     } 
    }) 
    } 

    render() { 
    const {handleSubmit} = this.props; 

    return (
     <div> 
     <img src={login_image} alt="Poink Logo"/> 
     <ErrorMessage 
      isAuthenticated={this.state.isAuthenticated} 
      message={this.state.message} 
     /> 

     <form onSubmit={handleSubmit(this.onSubmit.bind(this))}> 
      <Field 
      name="userid" 
      component={this.renderField} 
      placeholder="User ID" 
      type="text" 
      /> 
      <Field 
      name="password" 
      component={this.renderField} 
      placeholder="Password" 
      type="password" 
      /> 
      <button type="submit" className="btn btn-primary">Submit</button> 
     </form> 
     <a className='btn btn-primary' href="https://www.magicboxasia.com/">Sign up</a> 
     </div> 
    ); 
    } 
} 

function validate(values) { 
    const errors = {}; 

    // Validate the inputs from 'values' 
    if (!values.userid) { 
    errors.userid = "Enter a user ID!"; 
    } 

    if (!values.password) { 
    errors.password = "Enter your password"; 
    } 

    return errors; 
} 

function mapStateToProps(state) { 
    return { 
    token: state.token, 
    isAuthenticated: state.isAuthenticated, 
    } 
} 

export default reduxForm({ 
    validate, 
    form: 'LoginForm' 
})(
    connect(mapStateToProps, {getTokenAuth, refreshToken})(LoginPage) 
); 

答えて

1

ですトークンが秘密なしで有効かどうかを確認できません。

私が行ったことは、トークンが小道具として保存されているかどうかをチェックする機能を受け取る高次コンポーネントです。関数がtrueに戻ると、コンポーネントがレンダリングされ、ログインルートにリダイレクトされます。この機能はisAuthorizedと呼ばれます。

const PrivateRoute = ({ component: Component, isAuthorized, ...otherProps }) => (
<Route 
    {...otherProps} 
    render={props => (
     isAuthorized() ? (<Component {...props} />) : 
      (
       <Redirect to={ 
        { 
         pathname: '/login', 
         state: { from: props.location }, 
        } 
       } 
       /> 
      ) 
    )} 
/> 
); 

これは私たちのインデックスです。トークンが存在しない場合、ログインするユーザーをリダイレクトする

<Switch> 
    <PrivateRoute exact path="/" isAuthorized={hasToken} component={Home} /> 
    <PrivateRoute exact path="/list" isAuthorized={hasToken} component={List} /> 
    <PrivateRoute exact path="/view/:id" isAuthorized={hasToken} component={View} /> 
    <Route component={PageNotFound} /> 
</Switch> 

今そのPrivateRouteのresposability:私たちは、ユーザーが、この場合にhasTokenあるこのルートを、見ることが許可されている場合伝える機能をインポートします。

バックエンドが401(権限のない)を再試行する場合、ユーザーをログインにリダイレクトする良い方法を検討する必要があります。バックエンドは実際のトークンバリデータです。私が働いている会社では、Axisを使ってAjax呼び出しを行い、Axesインターセプタを作成して、バックエンドの応答が401 httpステータスコードを返した場合、ユーザーをログインルートにリダイレクトします。

+0

お待ちください。あなたの答えを理解するのに数日かかる場合。 – Sarit

+0

あなたの質問にもっと直接答えてみます。 1)いいえ、あなたはすべきではありません。フロントエンドはトークンが存在するかどうかをチェックするだけです。これは、フロントエンドの「権限があります」です。バックエンドは、各要求時にトークンを検証する必要があります。有効でないと判断した場合は、401を返します。フロントエンドは、バックエンドから401を受け取った場合、ログインページにリダイレクトする必要があります。私たちはAxiosインターセプタを使ってDRYを維持しました。 2)はい、各ルートコンポーネント(ページコンポーネント/コンテナ)では、トークンがレンダリングされる前にトークンが存在しないかどうかを確認する必要があります。私たちはこのPrivateRouteコンポーネントを使ってDRYを維持しました。 –

+0

私が間違った方法で行っている場合は、私を修正してください。私は今、私の ''を「コンテナ」にするつもりです。そして、 ' 'のすべてを' 'の状態にします。それによって私は 'props.location'を渡すことができます。私は、 'token'が期限切れになったときにloginページにユーザが追い出された最後のページであると考えます。したがって、ユーザが 'LoginForm'と成功を記入すると。彼は、もう一度ログインしたページを最後に押し出すために「押す」でしょう。 – Sarit

関連する問題