Ответ 1
Еще один способ - использовать JSON Web Tokens (JWT), которые требуются для каждого маршрута, и localStorage, чтобы проверить JWT.
TL; DR
-
На переднем конце у вас есть signin и signup маршрут, который запрашивает ваш сервер для JWT в соответствии с аутентификацией на сервере. однажды передал соответствующий JWT, вы должны установить свойство состояния для правда. У вас может быть маршрут выписки, который позволяет пользователю установить этот состояние false.
-
В index.js, который содержит ваши маршруты, можно проверить локальное хранилище перед рендерингом, тем самым устраняя вашу проблему с потерей состояния при обновлении, но сохраняя некоторую безопасность.
-
Все маршруты, требующие аутентификации в вашем приложении, отображаются через Компоновный Компонент, и обеспеченный необходимостью имеющих JWT в заголовке для авторизации в API сервера.
Настройка этого занимает немного времени, но это сделает ваше приложение "разумным" безопасным.
Чтобы решить вашу проблему:
Проверьте локальное хранилище перед маршрутами в вашем файле index.js
, как показано ниже, при необходимости обновив состояние для аутентификации.
Приложение поддерживает безопасность с тем, что API защищен JWT, который позволит решить проблему обновления и поддерживать безопасную ссылку на ваш сервер и данные.
Таким образом, в маршрутах у вас будет что-то вроде этого:
index.js
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
является составным компонентом, а Graph
и IsAuthenticated
(может быть любым числом соответствующих им компонентов) требует, чтобы state.authenticated
был истинным.
Компоненты, в этом случае Graph
и IsAuthenticated
отображаются, если значение state.authenticated
равно true. В противном случае по умолчанию возвращается корневой маршрут.
Затем вы можете создать составной компонент, подобный этому, через который отображаются все ваши маршруты. Он проверит, что состояние, в котором вы держите/нет аутентификацию пользователя (логическое), истинно перед рендерингом.
require_auth.js
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);
}
На стороне signup/signin вы можете создать действие, которое хранит 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 с конфиденциальной/защищенной информацией.
Создание и анализ JWT для пользователей API-интерфейса сервера - еще один шаг. Я нашел паспорт, чтобы быть эффективным.