简体   繁体   中英

keep user logged in when browser closes, not when it refreshes

I would like to 'keep user logged in' when user want to. so that user doesn't have to login every time he visits the website.

Here is how i did it. 1. when a user clicked 'keep me logged in' button, 'keepLoggedIn'state is set to 'true' in redux store which is persisted in local storage using 'redux-persist'. 2. In App.js, detect the window/tab close using window.onunload() and if 'keepLoggedIn' state is 'false', clear localStorage which will logout the user.

  • Issue window.onunload() also detects window refresh and reload. which leaves the user logged out.

  • Some thoughts

    1. some people suggests to add on keydown condition to detect refresh. but that does't cover when he clicks the refresh page button on the browser.

    2. Checking JWT token using window.onload ( which means making HTTPS request every refresh and reload page ) to login user again will be overkill.

Using window.onunload may not be the right approach. Is there a right and better workflow ?

App.js

const App = ({ messageShow, isOnModal, keepLoggedIn, children }) => {

  // keep me logged in when window/tab closed
    window.onbeforeunload = () => {
      window.onunload = () => {
        if (!keepLoggedIn) clearLocalStorage();
      };
      return undefined;
    };

  return (
    <div id="app absolute">
      <NavContainer />
       ...
      {children}
    </div>
  );
};

export default connect(
  mapPropsToState,
  null,
)(App);

---------------------------------- Edition --------------------------------

Store.js

import { applyMiddleware, createStore } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import { composeWithDevTools } from 'redux-devtools-extension';
import { routerMiddleware, connectRouter } from 'connected-react-router';
import createBrowserHistory from 'history/createBrowserHistory';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import storageSession from 'redux-persist/lib/storage/session';
import rootReducer from './src/reducers';

export const history = createBrowserHistory();

const middlewares = [
  routerMiddleware(history),
  thunkMiddleware,
  createLogger({
    predicate: () => process.env.NODE_ENV === 'development',
    collapsed: true,
  }),
];
const enhancers = [applyMiddleware(...middlewares)];

const persistConfig = {
  key: 'root',
  storage,
};

const persistedReducer = persistReducer(
  persistConfig,
  rootReducer(history), 
);

export default function configureStore(preloadedState) {
  const store = createStore(
    persistedReducer,
    preloadedState,
    composeWithDevTools(...enhancers),
  );
  const persistor = persistStore(store);
  return { store, persistor };
}

In order to use sessionStorage conditionally, I need to find a way to get redux state in store configuration. 'get.store()' won't work as persist needs to be configured before store.

const persistConfig = {
      key: 'root',
      keepLoggedIn ? storage : sessionStorage,
    };

For someone who may have the same question as me. I resolved it by using sessionStorage for "don't keep me logged in" and localStorage for "keep me logged in" as advised by @Jb31.

Here is how I worked around.

  1. changes 'keepLoggedIn' state(boolean) to true in redux store when "keep me logged in' checkbox clicks.

  2. if "don't keep me logged in", saves 'keepLoggedIn' state in sessionStorage when login submit button clicks.

    • Note: I am using redux-persist. so 'keepLoggedIn' state is auto-saved into localStorage.
const saveUserToken = (token, keepLoggedIn) => { 
  localStorage.setItem('token', token);

  return !keepLoggedIn ? 
    sessionStorage.setItem('keepLoggedIn',keepLoggedIn): null;
};
  1. Here is how you detect browser refresh when user 'keepLoggedIn' is false. Creates a HOC and add it to routes in order to render this HOC before renders any web pages you wish to protect. check if user reopen the browser and if it is, resets auth state & clears localStorage in order to logout the user. Otherwise, just returns a component to render a page.

    • If sessionStorage is empty, it means that the browser was reopened. (not refreshed.)

    • I also check if 'isLoggedIn' state(which is set to true when user log in) is false to make sure not to logout user when user is loggedIn.

routeGuards.js

  class LoginAuth extends React.Component {
    componentWillMount() {
      const {
        keepLoggedIn,
        isLoggedIn,
        userLogout,
        history,
      } = this.props;
      if (
        (!keepLoggedIn && !sessionStorage.getItem('keepLoggedIn')) || 
        !isLoggedIn
      ) {
        userLogout();
        clearStorage();
        return history.push('/login');
      }
    }

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

routes.js

const routes = props => (
  <div>
    <App history={props.history} />
    <Switch>
      <Route exact path="/" component={Home} />
      <LoggedOutRoute path="/login" component={Login} />
      <LoggedOutRoute path="/auth/forgot" component={Forgot} />
      <Route path="/reset" component={Reset} />
      <Route
        exact
        path="/user/account/me"
        component={RouteGuards(UserAccount)}
      />
      <Route component={NoMatch} />
    </Switch>
  </div>
);

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