简体   繁体   中英

React/Redux/Router - Auth0 login on load

I am creating a new React single page application and am trying to integrate with Auth0. I have been working with the React example but can't seem to get it working properly so that you are required to login immediately after the app loads. The problem I have now is that you are redirected to the login page twice because the app is rendering before the authentication is finished the first time. These are the important chunks of code:

index.js:

function initAuth(callback) {

  const auth = store.getState().app.auth;

  if(!auth.isAuthenticated()) {
    auth.login();
  }

  callback();

}

//Authorize the app and then render it
initAuth(function () {
  render(
    <Provider store={store}>
      <ConnectedRouter history={history}>
        <div>
          <App />
        </div>
      </ConnectedRouter>
    </Provider>,
    target
  );
});

app.js:

const App = props => (
  <div>
    //... Other stuff
    <Routes/>
    //... More stuff
  </div>
);

routes.js:

const Routes = props => (
  <main>
    <Switch>
      //...Other Routes Are Here
      <Route path="/callback" render={(props) => {
        return <Callback data={props} {...props} />;
      }}/>
      <Redirect from='*' to='/'/> {/*Any unknown URL will go here*/}
    </Switch>
  </main>
);

callback.js:

const auth = store.getState().app.auth;

const handleAuthentication = (nextState) => {
  console.log('Evaluation: ', /access_token|id_token|error/.test(nextState.location.hash))
  if (/access_token|id_token|error/.test(nextState.location.hash)) {
    auth.handleAuthentication();
  }
};

class Callback extends Component {

  componentDidMount() {
    handleAuthentication(this.props.data);
  }
  //... Render method etc
}

auth.js:

login() {
  this.auth0.authorize();
}

handleAuthentication() {
  this.auth0.parseHash((err, authResult) => {
    if (authResult && authResult.accessToken && authResult.idToken) {
      this.setSession(authResult);
      history.replace('/home');
    } else if (err) {
      history.replace('/home');
      alert(`Error: ${err.error}. Check the console for further details.`);
    }
  });
}

isAuthenticated() {
  // Check whether the current time is past the 
  // access token's expiry time
  let expiresAt = JSON.parse(localStorage.getItem('expires_at'));
  return new Date().getTime() < expiresAt;
}

Right now my app basically works. The only issue is that you are required to login twice because there is a race condition between the login response and the app load/check. Why it is happening makes perfect sense but I am not sure how best to fix it.

I keep a flag on state indicating that the application is booting. This flag is true until a few checks have been made including verifying if the user is already authenticated. This prevents rendering of any components and just shows a loading indicator. Once the booting flag has been set to false the router will render.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM