Javascript 使用react路由器的模态对话框身份验证

Javascript 使用react路由器的模态对话框身份验证,javascript,authentication,reactjs,react-router,Javascript,Authentication,Reactjs,React Router,我有react/redux/react路由器应用程序,包含公共和私有部分。 登录和注册表单显示为模式对话框,没有自己的路由 所需流量: 用户单击链接->当前页面将显示模式对话框->,如果成功将身份验证转换到链接页面,则将用户留在当前页面 如果没有当前页面,则显示索引页面并继续流 我尝试使用OnenterHook来归档这个文件,但据我所知,转换是在执行hook之前发生的。如果我尝试使用history.goBack()它会导致页面重新出现,看起来很糟糕 有没有办法在没有不必要的重定向和额外渲染调用的

我有
react/redux/react路由器
应用程序,包含公共和私有部分。 登录和注册表单显示为模式对话框,没有自己的路由

所需流量: 用户单击链接->当前页面将显示模式对话框->,如果成功将身份验证转换到链接页面,则将用户留在当前页面

如果没有当前页面,则显示索引页面并继续流

我尝试使用OnenterHook来归档这个文件,但据我所知,转换是在执行hook之前发生的。如果我尝试使用
history.goBack()
它会导致页面重新出现,看起来很糟糕


有没有办法在没有不必要的重定向和额外渲染调用的情况下解决这个问题?

好的-我想我想出了一个方法来处理这个问题,它涵盖了所有的情况。不过,它确实需要您有某种方式从几乎任何组件访问应用程序状态。我正在使用Redux。这还假设登录、注册等没有路由

我所做的是创建两个“包装器”组件。第一种方法包装任何不安全的路由,并将位置存储到状态值,以便我们始终有对最后一条不安全路由的引用

import { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { setRoute } from './redux/client/ducks/auth';

function mapDispatchToProps(dispatch) {
  return {
    setRoute: bindActionCreators(setRoute, dispatch)
  };
}

@connect(null, mapDispatchToProps)
export default class InsecureWrapper extends Component {

  componentDidMount() {
    const { location, setRoute } = this.props;
    setRoute(location.pathname);
  }

  render() {
    return (
      <div>
        {this.props.children}
      </div>
    )
  }
}
从'react'导入{Component};
从'react redux'导入{connect};
从“redux”导入{bindActionCreators};
从“./redux/client/ducks/auth”导入{setRoute};
功能图DispatchToprops(调度){
返回{
setRoute:bindActionCreators(setRoute,调度)
};
}
@连接(空,mapDispatchToProps)
导出默认类UnsecureWrapper扩展组件{
componentDidMount(){
const{location,setRoute}=this.props;
setRoute(location.pathname);
}
render(){
返回(
{this.props.children}
)
}
}
另一个包裹了所有的安全路线。它显示登录对话框(也可以在登录和注册之间来回切换)并防止内容显示,除非登录到应用程序

import { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from './redux/client/ducks/auth';

function mapStateToProps(state) {
  return {
    auth: state.auth
  };
}

function mapDispatchToProps(dispatch) {
  return {
    authActions: bindActionCreators(authActions, dispatch)
  };
}

@connect(
  mapStateToProps,
  mapDispatchToProps
)
export default class SecureWrapper extends Component {

  componentDidMount() {
    const { auth, authActions } = this.props;
    //see if user and if not prompt for login
    if(!auth.loggedIn) {
      authActions.openLogin();
    }
  }

  //close any open dialogs in case the user hit browser back or whatever 
  componentWillUnmount() {
    const { authActions } = this.props;
    authActions.resetAuthDialogs();
  }    

  render() {
    const { auth, children } = this.props;
    return (
        <div className="container">
          {auth.loggedIn &&
            {children} ||
            <span>YOU MUST BE LOGGED IN TO VIEW THIS AREA!</span>
          }
        </div>
    );
  }

}
从'react'导入{Component};
从'react redux'导入{connect};
从“redux”导入{bindActionCreators};
从“/redux/client/ducks/auth”导入*作为身份验证;
函数MapStateTops(状态){
返回{
auth:state.auth
};
}
功能图DispatchToprops(调度){
返回{
authActions:bindActionCreators(authActions,dispatch)
};
}
@连接(
MapStateTops,
mapDispatchToProps
)
导出默认类SecureWrapper扩展组件{
componentDidMount(){
const{auth,authoctions}=this.props;
//查看用户是否登录,如果没有,则提示登录
如果(!auth.loggedIn){
authActions.openLogin();
}
}
//关闭任何打开的对话框,以防用户回击浏览器或其他任何东西
组件将卸载(){
const{authActions}=this.props;
authoctions.resetAuthDialogs();
}    
render(){
const{auth,children}=this.props;
返回(
{auth.loggedIn&&
{儿童}||
您必须登录才能查看此区域!
}
);
}
}
然后在路线中,根据需要用包装纸包装它们

import App from './containers/App';
import Dashboard from './containers/Dashboard';
import Secure from './containers/Secure';
import AuthWrapper from './common/client/components/AuthWrapper';
import InsecureWrapper from './common/client/components/InsecureWrapper';

export default [
  {path: '/', component: App, //common header or whatever can go here
  childRoutes: [
    {component: InsecureWrapper,
      childRoutes: [ //<- ***INSECURE ROUTES ARE CHILDREN HERE***
        {path: 'dashboard', component: Dashboard}
      ]
    },
    {component: SecureWrapper,
      //***SECURE ROUTES ARE CHILDREN HERE***
      childRoutes: [
        {path: 'secure', component:Secure}
      ]
    }
  ]}
]
从“/containers/App”导入应用程序;
从“./containers/Dashboard”导入仪表板;
从“./containers/Secure”导入安全;
从“/common/client/components/AuthWrapper”导入AuthWrapper;
从“./common/client/components/unsecurewrapper”导入unsecurewrapper;
导出默认值[
{path:'/',component:App,//common header或任何可以放在这里的东西
儿童路线:[
{组件:不安全的包装器,
儿童路线:[//{
const{auth,authActions,pushPath}=this.props;
pushPath(auth.prevRoute);//来自我们保存的状态值
authoctions.closeLogin();
};
_handleLoginSubmit=(e)=>{
const{authActions}=this.props;
//做任何你需要登录这里
authoctions.closeLogin();
};
render(){
const{auth}=this.props;
返回(
...
)
}
}
很明显,我在使用ES6、Babel和webpack……但是这些原则应该在没有它们的情况下适用,因为不应该使用Redux(您可以将上一条路线存储在本地存储或其他地方)。此外,为了简洁起见,我省略了一些传递道具的中间组件


其中一些可能是功能组件,但为了显示更多细节,我留下了完整的部分。通过对其中一些内容进行抽象,也有一些改进的空间,但我再次留下多余的部分来显示更多细节。希望这会有所帮助!

如果没有先前的路线,我忘记了索引部分,但这只是推送/替换先前的route为空/null。虽然提供了相当不错的流来处理直接导航到私人页面的问题,但这对解决主要问题没有帮助-在当前页面上显示模式窗口,而不是在目标页面上。我正在寻找某种位置更改前回叫,但看起来我只需要扩展链接标记Yes,我想了很多,并且删除了onTransitionTo,还没有找到更好的方法来处理它。这确实非常接近,因为如果未登录,它会隐藏目标页面上的内容,并且除了登录之外,唯一的“退出”是取消返回到它们来自的页面(或“主页”)的路径。我的对话框可以从任何页面启动,因此这很好地工作,只需要将其保留在路线中的一个位置。很抱歉,对于您想要的内容,无法提供更多帮助。
import { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from './redux/client/ducks/auth';
import LoginDialog from './common/client/components/dialogs/LoginDialog';
import RegisterDialog from './common/client/components/dialogs/RegisterDialog';
// this could also be replacePath if you wanted to overwrite the history
import { pushPath } from 'redux-simple-router'; 

function mapStateToProps(state) {
  return {
    auth: state.auth
  };
}

function mapDispatchToProps(dispatch) {
  return {
    authActions: bindActionCreators(authActions, dispatch),
    pushPath: bindActionCreators(pushPath, dispatch),
  };
}

@connect(
  mapStateToProps,
  mapDispatchToProps
)
export default class AuthContainer extends Component {

  _handleLoginCancel = (e) => {
    const { auth, authActions, pushPath } = this.props;
    pushPath(auth.prevRoute); // from our saved state value
    authActions.closeLogin();
  };

  _handleLoginSubmit = (e) => {
    const { authActions } = this.props;
    // do whatever you need to login here
    authActions.closeLogin();
  };

  render() {
    const { auth } = this.props;
    return (
      <div>
        <LoginDialog
          open={auth.showLogin}
          handleCancel={this._handleLoginCancel}
          handleSubmit={this._handleLoginSubmit}
          submitLabel="Login"
        />
       ...
      </div>
    )
  }
}