登录后重定向路由器

时间:2018-08-30 14:50:11

标签: reactjs redux react-router

在尝试通过登录对我的react应用进行身份验证后,我试图找出如何将其重定向到正确的页面。

这是我的App.js文件,该文件带有路由(没有导入):

ReactDOM.render((
<Provider store={store}>
    <Router history={history}>
        <Switch>
            <PrivateRoute path="/test" component={Test} />
            <Route path="/login" component={Login}  />
            <PrivateRoute path="/" render={() => <h1>Welcome</h1>} />
        </Switch>
    </Router>
</Provider>
), document.getElementById('root'));

我正在使用PrivateRoute组件来确保对私有路由进行身份验证:

class PrivateRoute extends Route {
render() {
    const { component: Component, isAuthenticated } = this.props;

    let propsCopy = Object.assign({}, this.props);
    delete propsCopy.component;
    delete propsCopy.isAuthenticated;
    return (
        isAuthenticated
        ? <Component {...propsCopy} />
        : <Redirect to={{
            pathname: LOGIN_PATH,
            state: { from: this.props.location }
        }} />
    );
}
}

/**
 * Maps properties from Redux store to this component.
 * @param {Object} state Redux object
 * @return {Object} mapper properties
 */
function mapStateToProps(state) {
// pull out auth element from Redux store state
const { auth } = state;
// extract authenticated element from auth object
const { isAuthenticated } = auth;

return {
    isAuthenticated
}
}

export default connect(mapStateToProps)(PrivateRoute);

重定向到的“我的登录”组件(为示例而简化:

class LoginForm extends Component {

    constructor() {
        super();


        this.state = {
            email: '',
            password: '',
        }

        this.handleFormSubmit = this.handleFormSubmit.bind(this);


    }


    handleFormSubmit(event) {
        //event.preventDefault();

        const validation = this.validator.validate(this.state);
        this.setState({ validation });
        this.submitted = true;

        if (validation.isValid) {
            // submit form here
            this.props.loginUser({
                    email: this.state.email,
                    password: this.state.password
                });
        }
    }


    render() {

        return (

            // My login FROM code here
        )

    }
}

function mapStateToProps(state) {
    return {
        isFetching: state.auth.isFetching,
        loginError: state.auth.loginError,
        isAuthenticated: state.auth.isAuthenticated
    };
}

function mapDispatchToProps(dispatch, props, state) {
    return {
        loginUser: (credentials) => {
            dispatch(loginUser(credentials));
        },
    };
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);

现在,如果LoginForm为false,它将在重定向到isAuthenticated组件的地方起作用。我可以将登录表单提交到我的登录服务,并收到成功回复并设置isAuthenticated

我的问题是如何重定向到原始路线?重定向通常在哪里进行?我假设它从未在reducer中完成,所以必须在LoginForm组件中完成,对吗?

我知道有很多资源可以讨论整个登录流程,但是我找不到解决该问题的资源(这让我感到惊讶)。每个人都重定向到特定页面(“ /”,“ / home”等),但是我如何捕获并重定向到原始路由。

2 个答案:

答案 0 :(得分:1)

由于PrivateRoutefrom而发生重定向时,isAuthenticated组件正在false中存储先前的路由。 LoginFormisAuthenticated时,可以在true中使用它来重定向用户。只需从from中提取this.props.location.state,然后将其与Redirect中的react-router-dom组件结合使用。如果您登录this.props.location.state.from,将看到属性pathname包含用户试图以未经身份验证的状态进入的字符串路由路径,一旦身份验证成功,该路径可用于重定向它们。

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Redirect, withRouter } from 'react-router-dom';

class LoginForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      email: '',
      password: '',
    }

    this.handleFormSubmit = this.handleFormSubmit.bind(this);
  }


  handleFormSubmit(event) {
    event.preventDefault();

    const validation = this.validator.validate(this.state);
    this.setState({ validation });
    this.submitted = true;

    if (validation.isValid) {
      // submit form here
      this.props.loginUser({
        email: this.state.email,
        password: this.state.password
      });
    }
  }


  render() {
    const { from } = this.props.location.state || { from: { pathname: "/" } };
    const { isAuthenticated } = this.props;

    if (isAuthenticated) {
      return <Redirect to={from} />;
    }

    return (
      {* login from code *}
    );
  }
}

function mapStateToProps(state) {
  return {
    isFetching: state.auth.isFetching,
    loginError: state.auth.loginError,
    isAuthenticated: state.auth.isAuthenticated
  };
}

function mapDispatchToProps(dispatch, props, state) {
  return {
    loginUser: (credentials) => {
      dispatch(loginUser(credentials));
    },
  };
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LoginForm));

您可能需要很好地更新PrivateRoute组件,以确保它返回一个Route,这与react-router-dom example是一致的:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Redirect, withRouter } from 'react-router-dom';

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props =>
    rest.isAuthenticated ? (
      <Component {...props} />
    ) : (
      <Redirect
        to={{
          pathname: LOGIN_PATH,
          state: { from: props.location }
        }}
      />
    )
  }
  />
);    

const mapStateToProps = ({ auth: { isAuthenticated } }) => ({ isAuthenticated });

export default withRouter(connect(mapStateToProps)(PrivateRoute));

我创建了一个简化的StackBlitz,演示了实际的功能。

希望有帮助!

答案 1 :(得分:1)

@Alexander和@ bos570首先,我非常感谢您这样做的方式。有更好的方法,但是这里是一种以受控方式构建它的实现:

在您的index.js中:

import React from 'react';
import ReactDOM from 'react-dom';

import './styles.scss'; // it depends what styles you're using css,scss,jss
import App from './App';

ReactDOM.render(<App />, document.getElementById('app'));

在您的App.js中:

class App extends Component {

  state = {
    isAuthenticated: false,
  };

componentDidMount(){
//call authentication API here
// setState isAuthentication to true upon authentication success

}

render(){
return(
      <Provider store={store}>
        <BrowserRouter>{isAuthenticated ? <Routes /> : <Login />}</BrowserRouter>
      </Provider>
)}

您的Routes.js将在Switch中包含所有路由,除非API响应成功,否则它将一直显示加载屏幕。然后您将重新路由到基本的登录页面。

即使您已完成代码拆分,也不会在身份验证失败后从main.bundle.js上从网络下载任何捆绑软件。 当人们使用Redux就像编程中的各行各业时,我会看到人们。我知道您将来的身份验证实现将为您提供一个refreshToken,这就是身份验证API为我们所做的。您可以将其存储在localStorage中,如果有人在任何时候刷新浏览器,您都无法将其保留在redux中,因为我们知道redux在浏览器刷新后会丢失状态,因此需要这样做 localStorage 表演。明智地使用它,我真的很想与你们所有人进行转换,我们如何才能使其变得更好。

我希望这会对您有所帮助。并且也许redux将并排用于身份验证。在应用程序中实现身份验证时,我度过了愉快的时光。 欢呼声

已编辑保持原样。但是我们需要知道在哪一点,您需要 redux,localStorage,Context API