【问题标题】:Prevent routing in React when user manually changes url in browser tab当用户在浏览器选项卡中手动更改 url 时,防止在 React 中路由
【发布时间】:2018-01-30 06:29:00
【问题描述】:

当用户在浏览器选项卡中手动更改路线并按 Enter 键时,我遇到了一个问题。这迫使我的反应路由器导航到用户输入的状态。我想防止这种情况发生,并且只允许通过我通过在我的网站上单击按钮实现的流程进行路由。

我的某些屏幕需要只有当用户使用预期的流程浏览网站时才可用的数据。如果用户直接尝试通过手动更改 url 中的路线来导航到特定路线,那么他可能会跳过所需的流程,因此应用程序将中断。

其他情况,如果我想限制某些用户访问某些路由,但用户知道路径并在浏览器 url 中手动输入该路径,那么他将看到该屏幕但不应该。

【问题讨论】:

  • 您是否还想通过在 URL 字段中键入 "www.stackoverflow.com" 来阻止他们离开您的网站? 来自 stackoverflow 或其他网站的人应该允许他们选择要访问的页面吗?请考虑不要弄乱正常浏览器导航机制的工作方式。这不可避免地会导致糟糕的用户体验。
  • @ivarni : 问题详细解释。
  • 我宁愿建议需要流程中先前步骤中的任何数据的页面如果缺少该数据,则将用户重定向回流程的开始。当用户使用 F5/Ctrl+R 刷新浏览器或为页面添加书签并再次返回时,这也适用。这应该可以解决您的问题,而不必与浏览器的工作方式作斗争。
  • @ivarni 考虑过,但最终用户会觉得很烦。
  • @VishalGulati 你在使用 Redux 吗?

标签: reactjs react-router react-redux react-router-v4


【解决方案1】:

我所做的是使用上一页中的道具,如果该道具未定义(意味着用户没有遵循正当程序:) 呵呵)我只是将用户送回登录页面或任何地方。

【讨论】:

    【解决方案2】:

    您可以使用 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语句

    【讨论】:

    • 看起来不错,谢谢!对于我关于流量的第一个问题,这还不够。知道如何处理吗?
    • 您能否提供一些该流程的示例? react-router 中的 Link 组件具有名为 state 的嵌套属性,如果有帮助的话。例如,&lt;Link to={{ pathname: '/profile', state: { byButtonClick: true } }}&gt;My button&lt;/Link&gt;。然后在组件或 HOC 中,您可以像这样访问此状态:this.props.location.state.byButtonClick。如果不正确,则重定向用户。
    • 这将需要在所有受影响的组件中包含此检查。是否有任何其他解决方案可以让 React 路由器监听通过应用程序中的事件而不是手动更改完成的路由更改?
    • 抱歉,不知道这样的解决方案。
    【解决方案3】:

    这样的东西是合适的。您使用处理身份验证/上下文道具的包装来制作 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);
    }
    

    【讨论】:

      【解决方案4】:

      我建议使用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
      

      这样当用户手动导航到特定页面时,他不会有那个 redux 状态,因为它是内存中的状态,并且会被重定向到 redirectPath 路由。

      【讨论】:

        【解决方案5】:

        您可以将条件放入给定页面/屏幕的 useEffect 中,如果它没有所需的值,则将其推回.. 下面的示例

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-03
          • 1970-01-01
          • 1970-01-01
          • 2020-08-11
          • 2013-11-05
          • 2013-04-01
          • 2021-09-05
          • 2018-11-10
          相关资源
          最近更新 更多