在浏览器关闭时(而不是在刷新时)保持用户登录状态

时间:2019-07-17 10:24:16

标签: javascript reactjs redux local-storage

我想在用户需要时“保持用户登录”。这样,用户不必在每次访问该网站时都登录。

这是我的做法。 1.当用户单击“保持登录状态”按钮时,redux存储中的“ keepLo​​ggedIn”状态设置为“ true”,该存储使用“ redux-persist”存储在本地存储中。 2.在App.js中,使用window.onunload()检测到窗口/选项卡关闭,如果'keepLo​​ggedIn'状态为'false',则清除localStorage,这将注销用户。

  • 问题 window.onunload()还会检测窗口刷新和重新加载。从而使用户无法登录。

  • 一些想法

    1. 有些人建议添加keydown条件以检测刷新。但是当他单击浏览器上的“刷新页面”按钮时,这并没有涵盖。

    2. 使用window.onload(这意味着使HTTPS请求每个刷新和重新加载页面)再次登录用户来检查JWT令牌将是多余的。

使用window.onunload可能不是正确的方法。有没有正确,更好的工作流程?

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);

----------------------------------版本------------ --------------------

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 };
}

为了有条件地使用sessionStorage,我需要找到一种在存储配置中获取redux状态的方法。 “ get.store()”不起作用,因为需要在存储之前配置持久性。

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

1 个答案:

答案 0 :(得分:0)

对于可能与我有相同问题的人。 我通过使用@@ bb31建议的sessionStorage来“不要让我保持登录状态”,使用localStorage来“让我保持登录状态”来解决该问题。

这是我的工作方式。

  1. 在“保持登录状态”复选框单击时,在redux存储中将“ keepLo​​ggedIn”状态(布尔值)更改为true。

  2. 如果“不要让我保持登录状态”,则在单击登录提交按钮时将'keepLo​​ggedIn'状态保存在sessionStorage中。

    • 注意:我正在使用redux-persist。因此“ keepLo​​ggedIn”状态会自动保存到localStorage中。
const saveUserToken = (token, keepLoggedIn) => { 
  localStorage.setItem('token', token);

  return !keepLoggedIn ? 
    sessionStorage.setItem('keepLoggedIn',keepLoggedIn): null;
};
  1. 这是当用户'keepLo​​ggedIn'为false时检测浏览器刷新的方法。 创建一个HOC 并将其添加到路由中,以便在呈现要保护的任何网页之前呈现此HOC。 检查用户是否重新打开浏览器,如果是,请重置身份验证状态并清除localStorage以便注销用户。 否则,只需返回一个组件即可呈现页面。

    • 如果sessionStorage为空,则重新打开浏览器,也不刷新浏览器。

    • 我还检查'isLoggedIn'状态(在用户登录时设置为true)是否为false,以确保在用户登录时不注销用户。

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>
);
相关问题