Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-router redux how can i update state on load of page for authentication

I am using https://github.com/davezuko/react-redux-starter-kit as a starter kit and trying to introduce authentication into the starter app.

I have authentication working, it sets state.auth on login success, I then have an onEnter on my protected routes which calls isAuthenticated() to check if the user is authenticated.

This is where i get lost and I am not sure how to check both the state.auth.user and the localStorage.token to make sure things are set.

The way i see it, i need to account for two cases

  1. the user logged in, but then refreshed the page. This means the token is still in localStorage but state is wiped, so I'd need to reload the state by decoding the token and reinjecting it into state.auth.user
  2. the user isn't logged in, redirect them to the route /auth/login (this part i have working).

My problem is using the starter kit i do not know how to properly get to state/store within my routes file so i can check for that state.auth.user property.. or if thats even the right way to do it (maybe i should be using an action instead)?

redux/modules/auth.js

import { createAction, handleActions } from 'redux-actions';
import { pushPath } from 'redux-simple-router'
// ------------------------------------
// Constants
// ------------------------------------
export const LOGIN_REQUEST = 'LOGIN_REQUEST';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_FAILURE = 'LOGIN_FAILURE';
export const STORE_USER = 'STORE_USER';
export const IS_AUTHENTICATED = 'IS_AUTHENTICATED';

const initialState = {
  isFetching: false,
  isAuthenticated: false,
  user: {},
  token: ''
};

// ------------------------------------
// Actions
// ------------------------------------
export const requestLogin = createAction(LOGIN_REQUEST, (payload) => payload);
export const receiveLogin = createAction(LOGIN_SUCCESS, (payload) => payload);
export const invalidLogin = createAction(LOGIN_FAILURE, (payload) => payload);

export const isAuthenticated = () => {
  return !!getToken();
};

const getToken = () => {
  return localStorage.token;
};

const _decodeToken = (token) => {
  return window.atob(token.split('.')[1]);
};

const storeToken = (token) => {
  localStorage.token = token;
};

export const doLogin = (identity, password) => {
  return (dispatch, getState) => {
    dispatch(requestLogin({ identity, password }));
    // mock backend call
    setTimeout(function () {
      var token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZmlyc3ROYW1lIjoiQWRtaW4iLCJsYXN0TmFtZSI6ImlzdHJhdG9yIiwiZW1haWwiOiJhZG1pbkBhenN1cHJhcy5jb20iLCJjcmVhdGVkQXQiOiIyMDE1LTEyLTMwVDIxOjMyOjIxLjM1NloiLCJ1cGRhdGVkQXQiOiIyMDE1LTEyLTMwVDIxOjMzOjE3LjQzMloiLCJpZCI6IjU2ODQ0ZDY1Y2UzMjEyZTUwMWE3ZmNmNyIsImlhdCI6MTQ1MTUxNjU5N30.qpDmsnpMaHZy4QITS5IBPhPieNER7QHKSFWzsvulWC8';
      storeToken(token);
      dispatch(receiveLogin({ user: { username: 'admin', uid: 1 }, token }));
      dispatch(pushPath('/'));
    }, 3000);
  };
};

export const actions = {
  doLogin,
  isAuthenticated
};

// ------------------------------------
// Reducer
// ------------------------------------
export default handleActions({
  [LOGIN_REQUEST]: (state, { payload }) => {
    return {
      ...state,
      isFetching: true,
      isAuthenticated: false
    };
  },
  [LOGIN_SUCCESS]: (state, { payload }) => {
    return {
      ...state,
      isFetching: false,
      isAuthenticated: true,
      token: payload.token,
      user: payload.user
    };
  },
  [LOGIN_FAILURE]: (state, { payload }) => {
    return {
      ...state,
      isFetching: false,
      isAuthenticated: false,
      message: payload
    };
  }
}, initialState);

routes/index.js

import { Route, IndexRoute } from 'react-router';

// NOTE: here we're making use of the `resolve.root` configuration
// option in webpack, which allows us to specify import paths as if
// they were from the root of the ~/src directory. This makes it
// very easy to navigate to files regardless of how deeply nested
// your current file is.
import CoreLayout from 'layouts/CoreLayout';
import AuthLayout from 'layouts/AuthLayout';

import HomeView from 'views/HomeView';
import LoginView from 'views/auth/LoginView';

import { actions as authActions } from '../redux/modules/auth';

function isAuthenticated (nextState, replaceState) {
  if (authActions.isAuthenticated()) {
    replaceState({ nextPathname: nextState.location.pathname }, '/auth/login');
  }
}

export default (<Route>
  <Route path='/' component={CoreLayout} onEnter={isAuthenticated}>
    <IndexRoute component={HomeView} />
    <Route path='/panel' name='Panel' component={HomeView} />
  </Route>
  <Route path='/auth' component={AuthLayout}>
    <Route path='login' component={LoginView} />
  </Route>
</Route>);
like image 870
NDBoost Avatar asked Nov 29 '25 03:11

NDBoost


1 Answers

I have been using this solution with https://github.com/davezuko/react-redux-starter-kit

  1. Create AuthenticatedComponent https://github.com/joshgeller/react-redux-jwt-auth-example/blob/master/src/components/AuthenticatedComponent.js

  2. Config router component require authen: https://github.com/joshgeller/react-redux-jwt-auth-example/blob/master/src/routes/index.js

  3. Check token (page loading): https://github.com/joshgeller/react-redux-jwt-auth-example/blob/master/src/index.js

like image 193
Tien Nguyen Avatar answered Dec 01 '25 18:12

Tien Nguyen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!