javascript - 在将历史推送到路由器之前验证 token

标签 javascript reactjs callback

我相信这是一个非常简单的问题,但我不习惯 Async/callback 的世界。

我制作了 PrivateRoute 以保护我的资源不被未经身份验证的用户拍摄。如果我只检查存储中的 token。它通常会推送到资源。但它不包括过时的 token。然后我让它拍摄以在继续之前与后端进行验证。

问题:
axios 调用返回正确的值,但页面不会将经过身份验证的用户推送到正确的资源页面 console.log 显示 1 then 并停留在登录页面

App.js

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

function verifyToken(isAuthenticated){
  if (isAuthenticated) {
    axios.post(`${BACKEND_URL}/api-token-verify/`, {
      token: getAuthToken()
    }).then((res) => {
        console.log('then');
        return true;
      })
      .catch((err) => {
        console.log('err');
        return false;
      });
  } else {
    console.log('ahaha');
    return false;
  }
}

// Deal with an ordinary outdated token. Hacked one will be handle on individual component
function hasToken() {
  const token = localStorage.getItem('authToken');
  const isAuthenticated = !((token === undefined) | (token === null));

  return verifyToken(isAuthenticated);
}


class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <BrowserRouter>
          <Switch>
            <Route exact path='/' component={Login}/>
            <PrivateRoute exact path='/simulator/' isAuthorized={hasToken} component={Simulator}/>
          </Switch>
        </BrowserRouter>
      </Provider>
    )
  }
}

export default App;

问题:
我怎样才能让它像顺序一样运行?

答案:
感谢 m0meni 他的回答和评论解决了我的问题。这是我基于他的回答的解决方案。我决定把我的解决方案放在这里,因为将来我可能会忘记它。 我制作了新的 Component 并将其命名为 Container。因为我不能把 redux 放在这个级别。

class App extends Component {

  render() {
    return (
      <Provider store={store}>
        <Container/>
      </Provider>
    )
  }
}

Container.js

import React, {Component, Fragment} from 'react';
import {BrowserRouter, Redirect, Route, Switch} from 'react-router-dom';
import Simulator from "../../simulators/components/Simulators";
import Login from "../../frontpage/components/login";
import {connect} from 'react-redux';
import {CHECK_TOKEN} from "../../constants";

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


// Deal with an ordinary outdated token. Hacked one will be handle on individual component
function hasToken() {
  const token = localStorage.getItem('authToken');
  return !((token === undefined) | (token === null));
}


class Container extends Component {
  /*
  * In order to do redux staff and not to mess up with top most <App/>
  * Container has been created to contain them all
  *
  * */
  constructor(props) {
    super(props);
    this.props.validateToken();
  }

  render() {
    console.log(this.props);
    const {isAuthenticated, wrapper} = this.props;
    console.log(typeof this.props.wrapper);
    if((typeof this.props.wrapper) === 'function') {
      console.log('this is function');
      return (
        <Fragment>
          <BrowserRouter>
            <Switch>
              <Route exact path='/' component={Login}/>
              <PrivateRoute exact path='/simulator/' isAuthorized={this.props.wrapper} component={Simulator}/>
            </Switch>
          </BrowserRouter>
        </Fragment>
      )
    }else{
      console.log('wrapper is not a function');
      console.log(typeof this.props.wrapper);
      return null;
    }
  }
}

const mapStateToProps = ({verifyTokenReducer}, ownProps) => {
  return verifyTokenReducer
};

const validateToken = () => {
  return {
    type: CHECK_TOKEN,
    payload: undefined
  }
};

export default connect(mapStateToProps, {validateToken})(Container);

reducers.js

import {GOOD_TOKEN, INVALID_TOKEN} from "../constants";

function immediateReturnTrue(){
  return true;
}
function immediateReturnFalse(){
  return false;
}

export const VerifyTokenReducer = (state = {}, action) => {
  switch (action.type) {
    case GOOD_TOKEN:
      return {
        isAuthenticated: true,
        wrapper: immediateReturnTrue
      };
    case INVALID_TOKEN:
      return {
        isAuthenticated: false,
        wrapper: immediateReturnFalse
      };
    default:
      return state;
  }
};

最佳答案

这里的关键见解是 verifyToken永远返回 true 因为 if 分支不返回任何内容,而 else 分支返回 错误return true 在你的 promise 中是在 .then 的回调中,这意味着 return true 不适用于函数 verifyToken,而是.then里面的匿名函数。

为了解决这个问题,您需要从 verifyToken 函数返回 promise ,并在 PrivateRoute 组件中将其作为 promise 处理。现在,您的 render prop 将 promise 视为立即可用的值而不是 promise。 (你没有在任何地方使用 .then)

render={props => (
  isAuthorized() ? (<Component {...props} />) :
    (
      <Redirect to={
        {
          pathname: '/',
          state: {from: props.location},
        }
      }
      />
    )
)}

关于javascript - 在将历史推送到路由器之前验证 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50567273/

相关文章:

javascript - Node.js Q promise ,可以使用 this() 为什么要使用 defer()?

php - Javascript 字符串长度与 PHP mb_strlen 不同

javascript - 是否可以使用 material ui 选项卡并仍然使用 react router?

reactjs - 在 React Native 中的 const 中插入 if/else 语句的正确方法?

javascript - 列表中 React 元素的最佳键是什么?

callback - Rails Actioncable 成功回调

javascript - React Hook 表单 : Submit a form with nested components or extract fields of nested components to submit

javascript - 使用日期选择器的另一个字段中的日期自动填充新字段

Javascript:根据特定下拉列表的值隐藏表单输入

callback - 在 Rust 中实现多个可变(静态分配、静态分派(dispatch)等)回调的正确方法是什么?