Предотвращение маршрутизации в Реагировании, когда пользователь вручную изменяет URL-адрес на вкладке браузера
Я застрял в проблеме, которая возникает, когда пользователь вручную изменяет маршрут на вкладке браузера и нажимает клавишу ввода. Это заставляет мой реагирующий маршрутизатор перейти к состоянию, введенному пользователем. Я хочу предотвратить это и разрешить маршрутизацию только через поток, который я реализовал нажатием кнопки на моем веб-сайте.
Некоторые из моих экранов нуждаются в данных, которые будут доступны только в том случае, если пользователь перемещается по сайту с использованием ожидаемого потока. Если пользователь напрямую пытается перейти к определенному маршруту, вручную изменив маршрут в URL-адресе, он может пропустить нужный поток и, следовательно, приложение сломается.
Другой сценарий, если я хочу ограничить доступ некоторых пользователей к некоторым маршрутам, но пользователь знает путь и вручную вводит это в URL-адрес браузера, тогда он будет представлен с этим экраном, но не должен быть.
Ответы
Ответ 1
Вы можете создать защиту маршрута с помощью 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
Ответ 2
Что-то вроде этого подходит. Вы создаете HOC Route с оберткой для работы с реквизитами аутентификации/контекста.
Примечание. Это касается прямого доступа к маршруту, а не пунктов меню и т.д. Это должно быть обработано просто по компонентам 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);
}
Ответ 3
Что я делаю, так это использую реквизит с предыдущей страницы, если этот реквизит не определен (имеется в виду, что пользователь не выполнил должный процесс :) хе-хе), я просто отправляю пользователя обратно на целевую страницу или куда-либо еще.
Ответ 4
Я бы предложил использовать эту библиотеку для наиболее чистого решения (или, по крайней мере, сделать ее похожую реализацию в личном плане).
Затем вы создадите проверку подлинности 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))
Единственное, что важно, - это то, что вы корректно обновляете свое состояние редукса в процессе выполнения шага. Когда пользователь завершит первый шаг, вы установите
state.flow["first-step-finished"] = true // or however you manage your state
так, чтобы при переходе пользователя вручную на определенную страницу у него не было такого состояния избыточности, поскольку оно находилось в памяти и было перенаправлено на маршрут redirectPath
.