如何使用 Django 后端保持用户登录 React 应用程序

问题描述

我有一个非常著名的问题,我认为每个人都至少解决过一次。即使页面已刷新,我也想保留登录我的 React 应用程序的用户。我已经阅读了所有有关如何做到这一点的相关问题和文章,但不幸的是我一无所获。 在我的 ProtectedComponent 中,我有以下代码

const ProtectedRoute = ({ notLoggedInPath }) => {
  
  const isLoggedIn = useSelector((state) => state.auth.isLoggedIn);

  return (
    <Fragment>
      {isLoggedIn && <RecorderPage />}
      {!isLoggedIn && <Redirect to={notLoggedInPath} />}
    </Fragment>
  );
};

如您所见,我在我的身份验证减速器的初始状态中实现了一个名为 isLoggedIn 的变量,如果此变量为真,则受保护的路由将可访问,否则将无法访问。

在我的登录组件中,我将收到的令牌从 api 存储到 localStorage。这已经完全完成了。但我的主要问题是,当用户登录然后导航到受保护的路线时,通过刷新页面,我的 initialState(isLoggedIn) 消失并更改为 false,从而使用户退出。这在 ReactJS 的文化中是完全自然的。但是,我如何实现一种方法,在我的应用程序启动时,它会查找对先前收到的令牌进行身份验证,如果它尚未过期,则它将用户导航到应用程序刷新的页面。这是由大量网站完成的,所以我知道它可以完成。但我不知道如何?

我的登录组件:

const SignInForm = () => {
  const dispatch = usedispatch();
  const history = useHistory();

  const [username,setUsername] = useState('');
  const [password,setPassword] = useState('');

  const handleSubmit = () => {
    axios({
      method: 'post',url: 'someurl/api/token/',data: {
        username: username,password: password,},})
      .then((res) => {
        const token = res.data.access;
        localStorage.setItem('token',token);    
        dispatch(updateUserInStore(token,username));
        dispatch(makeUserLoggedIn());
        history.push('/recorder');
      })
      .catch((err) => {
        console.log(err);
        console.log(err.response);
      });
  };
return (
<some jsx/>
)

值得一提的是,我在我的母级组件App中也使用了钩子useEffect。我的意思是,当我的应用程序在 useEffect 中启动回调时,会检查 localStorage 令牌是否可以被授权,但由于 js 的异步性质以及 axios 请求,这不是解决方案,因为在收到此 axios 请求的响应之前设置了 initialState .

我的应用组件:

const App = () => {
  const dispatch = usedispatch();
  const history = useHistory();
  const tokenLocalStored = localStorage.getItem('token');

  const checkIfUserCanBeLoggedIn = () => {
    const token = localStorage.getItem('token');
    axios({
      method: 'get',url: 'some-url/api/sentence',headers: {
        Authorization: `Bearer ${token}`,})
      .then((res) => {
        dispatch(makeUserLoggedIn());
      })
      .catch((err) => {
        console.log(err);
        console.log(err.response);
        return false;
      });
  };

  useEffect(() => {
    checkIfUserCanBeLoggedIn();
  });

  return (
     <Some JSX>
)

解决方法

当页面重新加载时,执行 App.js 上 useEffect hook 中的异步逻辑。使用 authChecking 之类的状态在检查身份验证状态时显示加载程序。

const [authChecking,updateAuthChecking] = useState(true)

useEffect(() => {
  asyncFunc
  .then(updateUserObjToStore)
  .finally(() => updateAuthChecking(false))
},[])

我也在媒体上写了一篇关于这个的文章,如果你有任何疑问,请随时查看。 https://medium.com/@jmathew1706/configuring-protected-routes-in-react-using-react-router-af3958bfeffd

额外提示:尝试将此逻辑保留在自定义钩子中将确保正确分离关注点。