ユーザーがブラウザーのタブでルートを手動で変更してEnterキーを押すと発生する問題で立ち往生しています。これにより、反応ルーターはユーザーが入力した状態に移動します。これを防ぎ、自分のWebサイトのボタンクリックで実装したフローを介したルーティングのみを許可します。
一部の画面には、ユーザーが予想されるフローを使用してサイトをナビゲートした場合にのみ利用できるデータが必要です。ユーザーがURLのルートを手動で変更して特定のルートに直接移動しようとすると、目的のフローがスキップされる可能性があるため、アプリが機能しなくなります。
他のシナリオでは、一部のユーザーが一部のルートにアクセスできないように制限したいが、ユーザーはパスを知っていて手動でブラウザのURLに入力した場合、その画面が表示されますが、そうすべきではありません。
前のページの小道具を使用します。その小道具が定義されていない場合(つまり、ユーザーが適切なプロセスに従わなかったことを意味します:) hehe)ユーザーをランディングページまたはどこにでも送り返すだけです。
HOCを使用してルートガードを作成できます。たとえば、権限のないユーザーがルート/profile
を通過しないようにするには、次のようにします。
// requireAuthorized.js (HOC)
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import {Redirect} from 'react-router-dom'
const connector = connect(
state => ({
isAuthorized: state.profile !== null // say, you keep user profile in redux
})
)
export default (WrappedComponent) => {
return (
connector(
class extends Component {
static propTypes = {
isAuthorized: PropTypes.bool.isRequired
}
render () {
const {isAuthorized, ...clearedProps} = this.props
if (isAuthorized) {
return <WrappedComponent {...clearedProps} />
} else {
return <Redirect to={{pathname: '/login'}} />
}
}
}
)
)
}
// ProfilePage.jsx
import React from 'react'
...
import requireAdmin from '../hocs/requireAdmin' // adjust path
class ProfilePage extends React.Component {
...
render () {
return (
<div>
...
</div>
)
}
}
export default requireAdmin(ProfilePage)
私のProfilePage.js
のexportステートメントに注意してください
このようなものが適切です。認証/コンテキストプロップを処理するラップ機能でHOCルートを作成します。注:これは、メニュー項目などではなく、ルートへの直接アクセスを扱います。これは、menu/menuItemコンポーネントでも同様に扱う必要があります。
import requireAuth from "../components/login/requireAuth";
class Routes extends React.Component<RoutesProps, {}> {
render() {
return (
<div>
<Switch>
<Route exact={true} path="/" component={requireAuth(Persons, ["UC52_003"])} />
<Route path="/jobs" component={requireAuth(Jobs, ["UC52_006"])} />
</Switch>
</div>
)
}
}
export default function (ComposedComponent, privileges) {
interface AuthenticateProps {
isAuthenticated: boolean
userPrivileges: string[]
}
class Authenticate extends React.Component<AuthenticateProps, {}> {
constructor(props: AuthenticateProps) {
super(props)
}
render() {
return (
isAuthorized(this.props.isAuthenticated, privileges, this.props.userPrivileges) &&
<ComposedComponent {...this.props} /> || <div>User is not authorised to access this page.</div>
);
}
}
function mapStateToProps(state) {
return {
isAuthenticated: state.userContext ? state.userContext.isAuthenticated : false,
userPrivileges: state.userContext ? state.userContext.user ? state.userContext.user.rights : [] : []
};
}
return connect(mapStateToProps, null)(Authenticate);
}
最もクリーンな解決策として this library を使用することをお勧めします(または少なくとも個人的に同様の実装を行う)。
次に、認証チェックHOCを作成します。
export const withAuth = connectedReduxRedirect({
redirectPath: '/login',
authenticatedSelector: state => state.user.isAuthenticated, // or whatever you use
authenticatingSelector: state => state.user.loading,
wrapperDisplayName: 'UserIsAuthenticated'
});
そして、フローHOCを簡単に作成できます。
export const withFlow = (step) = connectedReduxRedirect({
redirectPath: '/initial-flow-step',
authenticatedSelector: state => state.flow[step] === true,
wrapperDisplayName: 'FlowComponent'
});
次に、コンポーネントを初期化します
const AuthenticatedComponent = withAuth(Dashboard)
const SecondStepComponent = withFlow("first-step-finished")(SecondStep)
const ThirdStepComponent = withFlow("second-step-finished")(ThirdStep)
HOCを構成することで、認証されたフローステップを簡単に作成できます。
const AuthSecondStepComponent = withAuth(withFlow("first-step-finished")(SecondStep))
重要なことは、ステップフローを実行するときにredux状態を正しく更新することだけです。ユーザーが設定した最初のステップを完了すると
state.flow["first-step-finished"] = true // or however you manage your state
そのため、ユーザーが特定のページに手動で移動したときに、メモリ状態であり、redirectPath
ルートにリダイレクトされるため、ユーザーはそのredux状態になりません。