在ReactJS Hooks中,当页面刷新时丢失了认证状态。

huangapple go评论84阅读模式
英文:

lost auth state when page refresh in reactjs hooks

问题

以下是您要翻译的代码部分:

当我使用有效的凭据登录时服务器会将JWT发送到浏览器我将这个JWT存储在本地存储中页面重定向到主页一切正常在主页上我有一个`loadUser`函数它发送请求到服务器以获取有效用户的用户详细信息但是当我刷新页面时主页永远不会执行因为认证状态返回为false页面从主页重定向到登录页面

这是App.js
import React, { Fragment } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Navbar from "./components/layout/Navbar";
import Home from "./components/pages/Home";
import Login from "./components/auth/Login";
import PrivateRoute from "./components/routing/PrivateRoute";
import "./App.css";

const App = () => {
  return (
    <AuthState>
      <Router>
        <Fragment>
          <Navbar />
          <div className="container">
            <Alerts />
            <Switch>
              <PrivateRoute exact path="/" component={Home} />
              <Route exact path="/login" component={Login} />
            </Switch>
          </div>
        </Fragment>
      </Router>
    </AuthState>
  );
};
export default App;

这是我的authState代码,成功登录后状态会从这里更改:

import React, { useReducer } from "react";
import axios from "axios";
import AuthContext from "./authContext";
import authReducer from "./authReducer";
import {
  USER_LOADED,
  AUTH_ERROR,
  LOGIN_SUCCESS,
  LOGIN_FAIL,
} from "../types";

const AuthState = (props) => {
  const initialState = {
    isAuthenticated: null,
    user: null,
  };
  const [state, dispatch] = useReducer(authReducer, initialState);

  // Load User
  const loadUser = async () => {
    if (localStorage.token) {
      setAuthToken(localStorage.token);
    }
    try {
      const res = await axios.get("/api/auth");
      dispatch({ type: USER_LOADED, payload: res.data });
    } catch (err) {
      dispatch({ type: AUTH_ERROR });
    }
  };

  // Login User
  const login = async (formData) => {
    const config = {
      headers: {
        "Content-Type": "application/json",
      },
    };
    try {
      const res = await axios.post("api/auth", formData, config);
      dispatch({
        type: LOGIN_SUCCESS,
        payload: res.data,
      });
      loadUser();
    } catch (err) {
      dispatch({
        type: LOGIN_FAIL,
        payload: err.response.data.msg,
      });
    }
  };

  return (
    <AuthContext.Provider
      value={{
        isAuthenticated: state.isAuthenticated,
        user: state.user,
        loadUser,
        login,
      }}
    >
      {props.children}
    </AuthContext.Provider>
  );
};
export default AuthState;

这是authReducer.js的减速器代码:

import {
  USER_LOADED,
  AUTH_ERROR,
  LOGIN_SUCCESS,
  LOGIN_FAIL,
} from "../types";

export default (state, action) => {
  switch (action.type) {
    case USER_LOADED:
      return {
        ...state,
        isAuthenticated: true,
        user: action.payload,
      };
    case LOGIN_SUCCESS:
      localStorage.setItem("token", action.payload.token);
      return {
        ...state,
        isAuthenticated: true,
      };
    case AUTH_ERROR:
    case LOGIN_FAIL:
      localStorage.removeItem("token");
      return {
        ...state,
        isAuthenticated: false,
        user: null,
      };
    default:
      return state;
  }
};

这是私有路由:

import React, { useContext } from "react";
import { Route, Redirect } from "react-router-dom";
import AuthContext from "../../context/auth/authContext";

const PrivateRoute = ({ component: Component, ...rest }) => {
  const authContext = useContext(AuthContext);
  const { isAuthenticated, loading } = authContext;

  return (
    <Route
      {...rest}
      render={(props) =>
        !isAuthenticated && !loading ? (
          <Redirect to="/login" />
        ) : (
          <Component {...props} />
        )
      }
    />
  );
};

export default PrivateRoute;

请注意,我已经将您提供的代码部分进行了翻译,如有需要,请随时提出更多问题。

英文:

When i login with valid credentials server send JWT to browser i store this JWT in localstore page redirect to home page everything works fine and in home page i have loadUser function which send request to server to get the user details of valid user but when i refresh the page it home page never execute because auth state returns to false and page redirect from home to login page
This is App.js
<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

 import React, { Fragment } from &quot;react&quot;;
import { BrowserRouter as Router, Route, Switch } from &quot;react-router-dom&quot;;
import Navbar from &quot;./components/layout/Navbar&quot;;
import Home from &quot;./components/pages/Home&quot;;
import Login from &quot;./components/auth/Login&quot;;
import PrivateRoute from &quot;./components/routing/PrivateRoute&quot;;
import &quot;./App.css&quot;;
const App = () =&gt; {
return (
&lt;AuthState&gt;
&lt;Router&gt;
&lt;Fragment&gt;
&lt;Navbar /&gt;
&lt;div className=&quot;container&quot;&gt;
&lt;Alerts /&gt;
&lt;Switch&gt;
&lt;PrivateRoute exact path=&quot;/&quot; component={Home} /&gt;
&lt;Route exact path=&quot;/login&quot; component={Login} /&gt;
&lt;/Switch&gt;
&lt;/div&gt;
&lt;/Fragment&gt;
&lt;/Router&gt;
&lt;/AuthState&gt;
);
};
export default App;

<!-- end snippet -->
This is my authsate code from where my state changes after successful login

import React, { useReducer } from &quot;react&quot;;
import axios from &quot;axios&quot;;
import AuthContext from &quot;./authContext&quot;;
import authReducer from &quot;./authReducer&quot;;
import {
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
} from &quot;../types&quot;;
const AuthState = props =&gt; {
const initialState = {
isAuthenticated: null,
user: null,
};
const [state, dispatch] = useReducer(authReducer, initialState);
// Load User
const loadUser = async () =&gt; {
if (localStorage.token) {
setAuthToken(localStorage.token);
}
try {
const res = await axios.get(&quot;/api/auth&quot;);
dispatch({ type: USER_LOADED, payload: res.data });
} catch (err) {
dispatch({ type: AUTH_ERROR });
}
};
// Login User
const login = async formData =&gt; {
const config = {
headers: {
&quot;Content-Type&quot;: &quot;application/json&quot;
}
};
try {
const res = await axios.post(&quot;api/auth&quot;, formData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
loadUser();
} catch (err) {
dispatch({
type: LOGIN_FAIL,
payload: err.response.data.msg
});
}
};
return (
&lt;AuthContext.Provider
value={{
isAuthenticated: state.isAuthenticated,
user: state.user,
loadUser,
login,
}}
&gt;
{props.children}
&lt;/AuthContext.Provider&gt;
);
};
export default AuthState;

This is reducer code authReducer.js

import {
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
} from &quot;../types&quot;;
export default (state, action) =&gt; {
switch (action.type) {
case USER_LOADED:
return {
...state,
isAuthenticated: true,
user: action.payload
};
case LOGIN_SUCCESS:
localStorage.setItem(&quot;token&quot;, action.payload.token);
return {
...state,
isAuthenticated: true
};
case AUTH_ERROR:
case LOGIN_FAIL:
localStorage.removeItem(&quot;token&quot;);
return {
...state,
isAuthenticated: false,
user: null,
};
default:
return state;
}
};
This is private route
import React, { useContext } from &quot;react&quot;;
import { Route, Redirect } from &quot;react-router-dom&quot;;
import AuthContext from &quot;../../context/auth/authContext&quot;;
const PrivateRoute = ({ component: Component, ...rest }) =&gt; {
const authContext = useContext(AuthContext);
const { isAuthenticated, loading } = authContext;
return (
&lt;Route
{...rest}
render={props =&gt;
!isAuthenticated &amp;&amp; !loading ? (
&lt;Redirect to=&quot;/login&quot; /&gt;
) : (
&lt;Component {...props} /&gt;
)
}
/&gt;
);
};
export default PrivateRoute;

答案1

得分: 1

可能是用于用户认证/授权的JSON Web令牌。您能否提供更多关于此的信息?

英文:

Probably the JSON web token which is used for user authentication/authorization. Can you give us more information about this?

答案2

得分: 1

这是可以预料的。

如果您想要持久保存令牌,应将其保存在 localStoragecookie 中。

然后,您应该在 componentDidMount 中或在使用 hooks 时在 useEffect 中(带有空依赖数组)检查令牌的存在和有效性。

如果您能告诉我们您在哪里发出 AJAX 请求,那将很好,例如,如果您正在使用 Axios,您可以在请求拦截器中封装这个逻辑。

英文:

That's to be expected.

If you want to persist the token you should save it in localStorage or a cookie.

Then, you should check for the token existence and validity in componentDidMount or in an useEffect (with a void dependency array) if you are using hooks.

It'd be nice if you could show us where you are making AJAX requests because if, for example, you are using Axios you can encapsulate this logic in a request interceptor.

huangapple
  • 本文由 发表于 2020年1月3日 14:45:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/59574290.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定