react-router(v2.8.1)およびES6構文を使用してReact。jsアプリケーション(v15.3)を作成しています。ユーザーが最初にログインする必要があるかどうかを確認するために、ページ間のすべての遷移をインターセプトするルーターコードを取得できません。
私のトップレベルのレンダリング方法は非常に簡単です(アプリも簡単です):
render()
{
return (
<Router history={hashHistory}>
<Route path="/" component={AppMain}>
<Route path="login" component={Login}/>
<Route path="logout" component={Logout}/>
<Route path="subject" component={SubjectPanel}/>
<Route path="all" component={NotesPanel}/>
</Route>
</Router>
);
}
Web上のすべてのサンプルはES5コードまたは古いバージョンのreact-router(バージョン2より古い)を使用しており、mixin(非推奨)およびwillTransitionTo(呼び出されない)でのさまざまな試みは失敗しました。
グローバルな「インターセプター機能」を設定して、ユーザーが要求したページに到達する前にユーザーに強制的に認証させるにはどうすればよいですか?
OnEnterコールバックのこのバージョンは、react-router(v2.8)で最終的に機能しました。
requireAuth(nextState,
replace)
{
if(!this.authenticated()) // pseudocode - SYNCHRONOUS function (cannot be async without extra callback parameter to this function)
replace('/login')
}
V1とv2のリアクションルーターリダイレクトの違いを説明するリンクは here です。以下に引用した関連セクション:
Likewise, redirecting from an onEnter hook now also uses a location descriptor.
// v1.0.x
(nextState, replaceState) => replaceState(null, '/foo')
(nextState, replaceState) => replaceState(null, '/foo', { the: 'query' })
// v2.0.0
(nextState, replace) => replace('/foo')
(nextState, replace) => replace({ pathname: '/foo', query: { the: 'query' } })
以下の完全なコードリスト(react-routerバージョン2.8.1):
requireAuth(nextState,
replace)
{
if(!this.authenticated()) // pseudocode - SYNCHRONOUS function (cannot be async without extra callback parameter to this function)
replace('/login');
}
render() {
return (
<Router history={hashHistory}>
<Route path="/" component={AppMain}>
<Route path="login" component={Login}/>
<Route path="logout" component={Logout}/>
<Route path="subject" component={SubjectPanel} onEnter={this.requireAuth}/>
<Route path="all" component={NotesPanel} onEnter={this.requireAuth}/>
</Route>
</Router>
);
}
すべてのルートには、ルート遷移が発生する前に呼び出されるonEnterフックがあります。カスタムrequireAuth関数でonEnterフックを処理します。
<Route path="/search" component={Search} onEnter={requireAuth} />
RequireAuthのサンプルを以下に示します。ユーザーが認証された場合、next()を介して移行します。それ以外の場合、パス名を/ loginに置き換え、next()を介して移行します。ログインには現在のパス名も渡されるため、ログインが完了すると、ユーザーは最初に要求されたパスにリダイレクトされます。
function requireAuth(nextState, replace, next) {
if (!authenticated) {
replace({
pathname: "/login",
state: {nextPathname: nextState.location.pathname}
});
}
next();
}
V4では、使用が認証されているかどうかを確認するルートコンポーネントを作成し、次のコンポーネントを返します。もちろん、次のコンポーネントは他のルートでもかまいません。
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Route, Redirect } from 'react-router-dom';
import AuthMiddleware from 'modules/middlewares/AuthMiddleware';
class PrivateRoute extends Component {
static propTypes = {
component: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool,
isLoggedIn: PropTypes.func.isRequired,
isError: PropTypes.bool.isRequired
};
static defaultProps = {
isAuthenticated: false
};
constructor(props) {
super(props);
if (!props.isAuthenticated) {
setTimeout(() => {
props.isLoggedIn();
}, 5);
}
}
componentWillMount() {
if (this.props.isAuthenticated) {
console.log('authenticated');
} else {
console.log('not authenticated');
}
}
componentWillUnmount() {}
render() {
const { isAuthenticated, component, isError, ...rest } = this.props;
if (isAuthenticated !== null) {
return (
<Route
{...rest}
render={props => (
isAuthenticated ? (
React.createElement(component, props)
) : (
<Redirect
to={{
pathname: isError ? '/login' : '/welcome',
state: { from: props.location }
}}
/>
)
)}
/>
);
} return null;
}
}
const mapStateToProps = (state) => {
return {
isAuthenticated: state.auth.isAuthenticated,
isError: state.auth.isError
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
isLoggedIn: () => AuthMiddleware.isLoggedIn()
}, dispatch);
};
export default connect(mapStateToProps, mapDispatchToProps)(PrivateRoute);