Reactjs 当用户在“浏览器”选项卡中手动更改url时,防止在“反应”中路由

Reactjs 当用户在“浏览器”选项卡中手动更改url时,防止在“反应”中路由,reactjs,react-router,react-redux,react-router-v4,Reactjs,React Router,React Redux,React Router V4,当用户在浏览器选项卡中手动更改管线并按enter键时,我遇到了一个问题。这将强制我的react路由器导航到用户输入的状态。我想防止这种情况,只允许通过我在网站上点击按钮实现的流程进行路由 我的一些屏幕需要的数据只有在用户使用预期的流导航站点时才可用。如果用户通过手动更改url中的路线直接尝试导航到特定路线,则他可能会跳过所需的流程,因此应用程序将中断 另一种情况是,如果我想限制某些用户访问某些路由,但用户知道路径,并在浏览器url中手动输入路径,则他将显示该屏幕,但不应显示该屏幕。您可以使用HO

当用户在浏览器选项卡中手动更改管线并按enter键时,我遇到了一个问题。这将强制我的react路由器导航到用户输入的状态。我想防止这种情况,只允许通过我在网站上点击按钮实现的流程进行路由

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


另一种情况是,如果我想限制某些用户访问某些路由,但用户知道路径,并在浏览器url中手动输入路径,则他将显示该屏幕,但不应显示该屏幕。

您可以使用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)
//requirereauthorized.js(HOC)
从“React”导入React,{Component}
从“道具类型”导入道具类型
从“react redux”导入{connect}
从“react router dom”导入{Redirect}
常数连接器=连接(
状态=>({
isAuthorized:state.profile!==null//比如说,您将用户配置文件保存在redux中
})
)
导出默认值(WrappedComponent)=>{
返回(
连接器(
类扩展组件{
静态类型={
未授权:PropTypes.bool.isRequired
}
渲染(){
const{isAuthorized,…clearedProps}=this.props
如果(未授权){
返回
}否则{
返回
}
}
}
)
)
}
//ProfilePage.jsx
从“React”导入React
...
从“../hocs/requireAdmin”//调整路径导入requireAdmin
类ProfilePage扩展了React.Component{
...
渲染(){
返回(
...
)
}
}
导出默认requireAdmin(配置文件页)

请注意my
ProfilePage.js

中的导出语句,类似这样的语句是合适的。您使用wrap-to函数创建HOC路由,该函数处理身份验证/上下文道具。 注意:这涉及直接访问路线,而不是菜单项等。必须在菜单/菜单项组件上以类似的方式处理

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);
}
从“./components/login/requireAuth”导入requireAuth;
类。组件{
render(){
返回(
)
}
}
导出默认功能(ComposedComponent、权限){
接口认证程序{
isAuthenticated:布尔值
用户权限:字符串[]
}
类身份验证扩展了React.Component{
构造函数(道具:AuthenticateProps){
超级(道具)
}
render(){
返回(
isAuthorized(this.props.isAuthentized,privileges,this.props.userPrivileges)&&
||用户无权访问此页面。
);
}
}
函数MapStateTops(状态){
返回{
isAuthenticated:state.userContext?state.userContext.isAuthenticated:false,
userPrivileges:state.userContext?state.userContext.user?state.userContext.user.rights:[]:[]
};
}
返回连接(mapstatetops,null)(身份验证);
}

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

我建议使用最干净的解决方案(或至少个人对其进行类似的实现)

然后您将创建身份验证检查:

export const withAuth = connectedReduxRedirect({
    redirectPath: '/login',
    authenticatedSelector: state => state.user.isAuthenticated, // or whatever you use
    authenticatingSelector: state => state.user.loading,
    wrapperDisplayName: 'UserIsAuthenticated'
});
您可以轻松地创建流程:

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)
您可以通过编写以下内容轻松创建经过身份验证的流:

const AuthSecondStepComponent = withAuth(withFlow("first-step-finished")(SecondStep))
唯一重要的是,在执行步骤流时正确地更新redux状态。当用户完成您设置的第一步时

state.flow["first-step-finished"] = true // or however you manage your state

这样,当用户手动导航到特定页面时,他就不会有这种redux状态,因为这是一种内存状态,会被重定向到
redirectPath
route。

您还想通过在URL字段中键入“www.stackoverflow.com”来阻止他们离开您的站点吗?对于来自stackoverflow或其他网站的人,他们应该允许选择要访问的页面吗?请考虑不要弄乱普通浏览器导航机制的工作原理。它不可避免地会导致用户体验不佳。@ivarni:问题已详细解释。我更愿意建议,如果数据丢失,需要流中以前步骤中的任何数据的页面会将用户重定向回流的开头。当用户使用F5/Ctrl+R刷新浏览器,或为页面添加书签,然后下次再回来时,这也适用。这应该可以解决您的问题,而不必与浏览器的工作方式作斗争。@ivarni考虑过这一点,但这对最终用户来说会很烦人。@VishalGulati您在使用Redux吗?看起来不错,谢谢!这还不足以解决我关于流的第一个问题。你知道如何处理吗?你能提供一些流程的例子吗<
react router
中的code>Link组件具有名为
state
的嵌套属性(如果有帮助)。例如,
My按钮
。然后在component或HOC中,您可以像这样访问此状态:
this.props.location.state.ByButton单击
。如果不正确,则重定向user.com,这将需要在所有受影响的组件中包含此检查。有没有其他解决方案可以让React路由器监听通过应用程序中的事件而不是手动更改完成的路由更改?对不起,不知道这样的解决方案。