另一種方法是使用每個路由所需的JSON Web Tokens (JWT)和localStorage來檢查JWT。
TL; DR
在前端您有根據服務器上的認證查詢您的 服務器的JWT一個登入和註冊的路線。一旦 通過適當的JWT,您將設置一個狀態屬性爲 true。您可以使用註銷路線,以允許用戶將此 狀態設置爲false。
包含您的路由的index.js可以在渲染前檢查本地存儲 ,從而消除刷新時丟失狀態 的問題,但保持一定的安全性。
在你的應用需要認證的所有路由都通過組合組件呈現 ,並用具有JWTs 的在服務器上的API授權頭的必要性擔保。
設置它需要一點時間,但它會使您的應用程序'合理''安全。
解決你的問題:
在index.js
文件的路徑之前,檢查本地存儲,如下圖所示,更新狀態,如果需要認證。
該應用程序通過JWT保護API解決您的刷新問題並維護與您的服務器和數據的安全鏈接這一事實來維護安全。
因此在路由你會有這樣的事情:
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
爲真。
如果state.authenticated
爲真,則組件在此示例中爲Graph
和IsAuthenticated
。否則默認回到根路由。
然後你可以像這樣構建一個組合組件,通過它來渲染你所有的路由。它將在渲染之前檢查你所持有的用戶是否被認證(布爾)的狀態。
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);
}
在註冊/登入側,你可以創建一個存儲JWT,並建立通過行動的創建者,以驗證狀態的動作 - >終極版店。此示例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.
在你的例子中,IsAuthenticated是ComposedComponent,是否正確? – klode
'RequiredAuth'是組成組件,而'IsAuthenticated'可以是任何數量的需要'state.authenticated'爲true的命名組件。更新了答案。 – alexi2
謝謝,新編輯更清晰。 – klode