frontend
の部分を設計中です。ここに私ですRouter
/
はログインページです。それはlocalStorage
の横のtoken
をチェックします。そして、それはstate
ルータのコンポーネント状態を別のルータコンポーネントに渡す方法
/select-teams
でisAuthenticated
機能ページで、LETのユーザーがそれを使用する前に、それは最初token
を検証する必要があります。
質問は次のとおりです。
query
APIs
の前に毎回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
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)
);
お待ちください。あなたの答えを理解するのに数日かかる場合。 – Sarit
あなたの質問にもっと直接答えてみます。 1)いいえ、あなたはすべきではありません。フロントエンドはトークンが存在するかどうかをチェックするだけです。これは、フロントエンドの「権限があります」です。バックエンドは、各要求時にトークンを検証する必要があります。有効でないと判断した場合は、401を返します。フロントエンドは、バックエンドから401を受け取った場合、ログインページにリダイレクトする必要があります。私たちはAxiosインターセプタを使ってDRYを維持しました。 2)はい、各ルートコンポーネント(ページコンポーネント/コンテナ)では、トークンがレンダリングされる前にトークンが存在しないかどうかを確認する必要があります。私たちはこのPrivateRouteコンポーネントを使ってDRYを維持しました。 –
私が間違った方法で行っている場合は、私を修正してください。私は今、私の ' 'を「コンテナ」にするつもりです。そして、 ' 'のすべてを' 'の状態にします。それによって私は 'props.location'を渡すことができます。私は、 'token'が期限切れになったときにloginページにユーザが追い出された最後のページであると考えます。したがって、ユーザが 'LoginForm'と成功を記入すると。彼は、もう一度ログインしたページを最後に押し出すために「押す」でしょう。 –
Sarit