简体   繁体   中英

How to keep user logged in in React app with a Django back-end

I have a very famous problem which I think everybody has at least once tackled. I want to persist the user logged-in in my react app even if the page is refreshed. I have read all the related questions and articles about how this can be done but unfortunately I got nowhere. In my ProtectedComponent I have the following code:

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

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

As you can see I have implemented a variable so-called isLoggedIn in my initialState of auth reducer and if this variable is true the protected route will be accessible otherwise not.

In my Sign In component I store the received token from the api to the localStorage. This is completely done. But my main question is that when the user signs in and then navigates to a protected route, by refreshing the page my initialState(isLoggedIn) goes away and changes to false, making the user logged out. This is completely natural in the culture of ReactJS. But how can I implement a way in which when my app is being launched, it looks for authenticating the previously received token and if it has not expired yet it navigates the user to the page on which the app is refreshed. This is done by a gigantic number of websites so I know it can be done. But I don't know how?

My sign in component:

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

It is worth mentioning that I have also used the hook useEffect in my mother-level component App. I mean when my app launches the callback in useEffect checks if the localStorage token can be authorised or not but because of async nature of js and also axios request this is not a solution since the initialState is set before the response of this axios request is received.

My App component:

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

When the page reloads execute the async logic in useEffect hook on App.js. Use a state like authChecking to show a loader while the auth state is being checked.

const [authChecking, updateAuthChecking] = useState(true)

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

I have also written a article on medium about this feel free to check it out if you have any doubts. https://medium.com/@jmathew1706/configuring-protected-routes-in-react-using-react-router-af3958bfeffd

Bonus tip: Try to keep this logic in a custom hook will ensure proper separation of concerns.

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