模式对话框使用react-router进行身份验证

时间:2016-01-20 18:50:08

标签: javascript authentication reactjs react-router

我有 public 私有部分的react/redux/react-router个应用程序。 登录和注册表单显示为模式对话框,没有自己的路由。

所需流程: 用户点击链接 - > 模式对话框显示在当前页面 - > 上,以便成功授权转换为链接页面,否则将用户留在当前页面。

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

我试图使用onEnter钩子将其归档,但据我所知,在执行钩子之前会发生转换。如果我尝试使用history.goBack()它会导致页面重新呈现并且看起来很讨厌。

如果没有不必要的重定向和额外的渲染调用,有没有办法解决这个问题?

1 个答案:

答案 0 :(得分:1)

好的 - 我想我想出了一种处理这个问题的方法,涵盖了所有的案例。它确实需要您通过某种方式从几乎任何组件访问应用程序状态。我正在使用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>
    )
  }
}

另一个包装所有安全路线。它显示登录对话框(也可以在登录和注册之间来回切换等),并防止显示内容,除非登录到应用程序...

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>
    );
  }

}

然后在路线中,根据需要将它们包装在包装中......

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}
      ]
    }
  ]}
]

最后但并非最不重要......在对话框中,您需要通过将位置推送(或替换)到保存的状态值来处理取消。当然,成功登录后,请关闭它们......

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>
    )
  }
}

我显然正在使用ES6,Babel和webpack ......但是原则应该在没有它们的情况下应用,因为不应该使用Redux(您可以将prev路由存储在本地存储中等等)。此外,为了简洁起见,我遗漏了一些传递道具的中间组件。

其中一些可能是功能组件,但我将它们留满了以显示更多细节。通过抽象其中一些内容也有一些改进的余地,但我再次将其留下来以显示更多细节。希望这有帮助!