如何通过isAuthenticated让Authenticated Component路由到受保护的路由?

时间:2018-02-20 09:18:27

标签: reactjs graphql react-router-v4

我正在通过反应路由器v4实现受保护的路由。 我正在尝试将“isAuthenticated”值从“Login”组件传递给“Authenticated”组件,但我得到“false”值。

也许我用错了方法,有人可以帮忙解决这个问题吗?

我的代码如下:

Login.js提供“isAuthenticated”控件

import React, { Component } from 'react';
import { AUTH_TOKEN } from '../constants';
import { USERNAME } from '../constants';
import { graphql, compose } from 'react-apollo';
import { Row, Col, FormGroup, ControlLabel, Button } from 'react-bootstrap';
import gql from 'graphql-tag';

export const Auth = {
    isAuthenticated: false,
  authenticate(cb) {
    this.isAuthenticated = true;
    // setTimeout(cb, 100);
  },
  signout(cb) {
    this.isAuthenticated = false;
    // setTimeout(cb, 100);
  }
};

class Login extends Component {
  state = {
    username: '',
    password: '',
  };

    login = () => {
        Auth.authenticate();
        console.log(Auth.isAuthenticated);
    };

  render() {

    return (
      <Row>
        <Col xs={12} sm={6} md={5} lg={4}>
                    <div className="Login">
                <h4 className="page-header">Login</h4>
                  <form ref={form => (this.form = form)} onSubmit={event => event.preventDefault()}>
                    <FormGroup>
                        <ControlLabel>Username</ControlLabel>
                        <br />
                    <input
                            value={this.state.username}
                            onChange={e => this.setState({ username: e.target.value })}
                          type="text"
                          autoFocus
                      />
                    </FormGroup>

                    <FormGroup>
                        <ControlLabel>Password</ControlLabel>
                        <br/>
                        <input
                            value={this.state.password}
                        onChange={e => this.setState({ password: e.target.value })}
                            type="password"
                          />
                        </FormGroup>
                      <div onClick={() => {this._confirm(); this.login(); }}>
                          <Button type="submit" bsStyle="success">Login</Button>
                      </div>
                    </form>
                </div>
            </Col>
        </Row>
  )
};

  _confirm = async () => {
    const { username, password } = this.state;

      const result = await this.props.loginMutation({
        variables: {
          username,
          password,
        },
      });

      const { token } = result;
      this._saveUserData(token, username);

        this.props.history.push(`/`);
  }

  _saveUserData = (token, username) => {
    localStorage.setItem(AUTH_TOKEN, token);
    localStorage.setItem(USERNAME, username);
  }
};

const LOGIN_MUTATION = gql`
  mutation LoginMutation($username: String!, $password: String!) {
    loginMutation(username: $username, password: $password) {
      token
    }
  }
`;

export default compose(
  graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
)(Login);

Authenticated.js需要获取“isAuthenticated”值(true)才能呈现受保护的路由。

import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { Auth } from '../pages/Login';

console.log(Auth.isAuthenticated);

class Authenticated extends Component {
  render() {
        const {
            component: Component, exact, ...rest
        } = this.props;

        return (
        <Route
            {...rest}
            exact={exact}
            render={props => (
            Auth.isAuthenticated ? (
                <Component { ...props} />
            ) : (
                <Redirect to="/login" />
        ))}
        />
        );
    }
}



export default Authenticated;

===解决方案解决方案===

Authenticated.js - &gt;从localStorage获取值

import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AUTH_TOKEN, IS_AUTHEN } from '../constants';

class Authenticated extends Component {


  render() {
        const {
            component: Component, exact, ...rest
        } = this.props;
        const isAuthenticated = !!localStorage.getItem(IS_AUTHEN) && !!localStorage.getItem(AUTH_TOKEN);
        console.log(isAuthenticated);

        return (
        <Route
            {...rest}
            exact={exact}
            render={props => (
            isAuthenticated ? (
                <Component { ...props} />
            ) : (
                <Redirect to="/login" />
        ))}
        />
        );
    }
}



export default Authenticated;

Login.js - &gt;使用localStorage.setItem存储值

import React, { Component } from 'react';
import { AUTH_TOKEN, USERNAME, IS_AUTHEN } from '../constants';
import { graphql, compose } from 'react-apollo';
import { Row, Col, FormGroup, ControlLabel, Button } from 'react-bootstrap';
import gql from 'graphql-tag';

class Login extends Component {
  state = {
    username: '',
    password: '',
    authenticated: false,
  };

  render() {

    return (
      <Row>
        <Col xs={12} sm={6} md={5} lg={4}>
                    <div className="Login">
                <h4 className="page-header">Login</h4>
                  <form ref={form => (this.form = form)} onSubmit={event => event.preventDefault()}>
                    <FormGroup>
                        <ControlLabel>Username</ControlLabel>
                        <br />
                    <input
                            value={this.state.username}
                            onChange={e => this.setState({ username: e.target.value })}
                          type="text"
                          autoFocus
                      />
                    </FormGroup>

                    <FormGroup>
                        <ControlLabel>Password</ControlLabel>
                        <br/>
                        <input
                            value={this.state.password}
                        onChange={e => this.setState({ password: e.target.value })}
                            type="password"
                          />
                        </FormGroup>
                      <div onClick={() => this._confirm()}>
                          <Button type="submit" bsStyle="success">Login</Button>
                      </div>
                    </form>
                </div>
            </Col>
        </Row>
  )
};

  _confirm = async () => {
    const { username, password } = this.state;

      const result = await this.props.loginMutation({
        variables: {
          username,
          password,
        },
      });

      this.setState({ authenticated: true });
      const { token } = result;
      this._saveUserData(token, username, this.state.authenticated);

        this.props.history.push(`/channel`);
  }

  _saveUserData = (token, username, authenticated) => {
    localStorage.setItem(AUTH_TOKEN, token);
    localStorage.setItem(USERNAME, username);
    localStorage.setItem(IS_AUTHEN, authenticated);
  }
};

const LOGIN_MUTATION = gql`
  mutation LoginMutation($username: String!, $password: String!) {
    loginMutation(username: $username, password: $password) {
      token
    }
  }
`;

export default compose(
  graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
)(Login);

1 个答案:

答案 0 :(得分:0)

首先,在应用程序的开头(index.js),我检查令牌并在我的状态中设置is_auth,就像这样

<!-- ls is LocalStorageService for get and set from localStorage-->

    if (ls.getUserDetails() && ls.getUserDetails().roles && ls.getUserDetails().roles.length) {
      store.dispatch({ type: SET_USER_ROLE, role: ls.getUserDetails().roles[0] });
      if (ls.getToken()) {
        store.dispatch({ type: AUTHENTICATE_USER, auth: true });
      }
    }
    else {
      store.dispatch({ type: AUTHENTICATE_USER, auth: false });
    }

然后,我制作了一个AuthGuard来验证登录状态,(通过将状态&#39; auth映射到这个类的道具)

AuthGuard.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux'
import { store } from '../stores/configureStore';

export default function (ComposedComponent) {

    // If user not authenticated render out to root

    class AuthGuard extends Component {
        static contextTypes = {
            router: React.PropTypes.object.isRequired
        };

        componentWillMount() {
            if (!this.props.authenticated) {
                //hashHistory.push('#/login');
                store.dispatch(push('/login'));
            }
        }

        componentWillUpdate(nextProps) {
            if (!nextProps.authenticated) {
                //hashHistory.push('#/login');
                store.dispatch(push('/login'));
            }
        }

        render() {
            return <ComposedComponent {...this.props} />;
        }
    }

    const mapStateToProps = (state) => ({
        authenticated: state.auth.auth
    });

    return connect(mapStateToProps)(AuthGuard);
}

然后在我的App.js中,我做路由,

App.js

<!--PROTECTED ROUTES GO AFTER '/app/'-->
        <Route path={`${match.url}app`} component={authGuard(MainApp)} /> 

<!--UNPROTECTED ROUTES GO AFTER '/' LIKE BELOW-->
        <Route exact path="/404" component={Page404} />
        <Route exact path="/403" component={Page403} />
        <Route exact path="/500" component={Page500} />
        <Route exact path="/confirm-email" component={PageConfirmEmail} />
        <Route exact path="/forgot-password" component={PageForgotPassword} />
        <Route exact path="/fullscreen" component={PageFullscreen} />
        <Route exact path="/lock-screen" component={PageLockScreen} />
        <Route exact path="/login" component={PageLogin} />
        <Route exact path="/sign-up" component={PageSignUp} />

以下评论,对于任何问题:)