持续基于React Cookie的身份验证状态

时间:2020-05-28 18:11:24

标签: reactjs cookies react-router jwt session-cookies

我正在使用React-Router和Redux构建身份验证流,其中后端以会话Cookie(带有Set-Cookie HTTP标头)的形式返回JWT,前端使用该JWT发出后续请求。 (我不使用localStorage作为一般建议是首选Cookie,因为在XSS情况下JS可能会读取它)

// my App component
  const { isAuthenticated } = useSelector((state) => state.user);

          <Container>
            {!isAuthenticated ? (
              <LoginForm />
            ) : (
              <Switch>
                <Route exact path="/" component={MessageList} />
                <Route path="/messages" component={MessageList} />
                <Route path="/login" component={LoginForm} />
                <Route path="/message/:id" component={MessageContainer} />
              </Switch>
            )}
          </Container>
// the api requests themselves abstracted
const login = (data) =>
  axios
    .post("auth/login", data, { withCredentials: true })
    .then((response) => response.data);

const fetchItems = (page, token) =>
  axios(`message/list/page/${page}`, {
    withCredentials: true,
  }).then((response) => response.data);
// actions
function handleError(err) {
  return {
    type: "ERROR_OCCURED",
    payload: err,
  };
}

function shouldFetchMessages(state, page) {
  if (!state.message.all.length) {
    return true;
  } else if (state.message.isFetching) {
    return false;
  } else {
    return state.message.all;
  }
}

export let getMessages = (page = 1) => async (dispatch, getState) => {
  let err, response;

  dispatch(requestMessages(page));
  [err, response] = await to(api.fetchItems(page, getState().user.accessToken));
  if (err) {
    return handleError(err);
  }
  return dispatch(receiveMessages(response));
};

export function getMessagesIfNeeded(page) {
  return (dispatch, getState) => {
    if (shouldFetchMessages(getState(), page)) {
      return dispatch(getMessages(page));
    }
  };
}
// reducer
// where would the localStorage isAuthenticated value be synced with the store?
export default (state = defaultState, action) => {
  switch (action.type) {
    // skipped the other reducers for brevity
    case "ERROR_OCCURED":
      return {
        ...state,
        isAuthenticated: false, // this should be saved in the localStorage
      };
    default:
      return state;
  }
};

我需要有一个BOOLEAN来容纳isAuthenticated的“状态”,以便显示适当的组件。

我的主要问题是Redux状态在页面刷新过程中当然不会持久。

我想到了一个localStorage变量(或新的cookie)。 (包含JWT的Cookie为httpOnly,根据我的理解,JavaScript无法访问该Cookie)。

问题:

  • 这是惯例吗
  • 如何处理JWT到期? (我想如果HTTP请求以401失败,我可以将其设置为false。)
  • localStorage变量将在哪里与Redux状态同步,以避免在我的Reducers中产生副作用?

1 个答案:

答案 0 :(得分:0)

我绝对不是这方面的专家,但在我的应用程序中,每当我设置或删除 httpOnly JWT cookie 时,我还会设置/删除一个常规 cookie,其中包含有关用户是否登录及其角色的信息.然后,您可以在客户端检查一些内容,而不会暴露任何敏感内容。