Can still access login page after logging in using ReactJS and dj-rest-auth

41 views Asked by At

I'm using dj-rest-auth for the authentication endpoints in my django project and reactjs in the frontend of my project. What happens if after I login, the user can still go to the /login page which should not.

Here's my LoginForm code:

import React, { useState } from 'react';
import { Form, Button, Alert, Container } from 'react-bootstrap';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';

const LoginForm = () => {
  const navigate = useNavigate();
  const [credentials, setCredentials] = useState({ username: '', password: '' });
  const [error, setError] = useState(null);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setCredentials((prevCredentials) => ({ ...prevCredentials, [name]: value }));
  };

  const validateCredentials = () => {
    if (credentials.username.length < 4) {
      setError('Username must be longer than 4 characters.');
      return false;
    }

    if (credentials.password.length < 8) {
      setError('Password must be at least 8 characters.');
      return false;
    }

    return true;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!validateCredentials()) {
      return;
    }

    try {
      const response = await axios.post('http://localhost:8000/api-auth/login/', credentials);
      const token = response.data.token;

      localStorage.setItem('token', token);
      navigate('/rants');
    } catch (error) {
      handleLoginError(error);
    }
  };

  const handleLoginError = (error) => {
    console.log(error.response);

    if (error.response && error.response.status === 400) {
      const errorMessage = error.response.data.non_field_errors
        ? error.response.data.non_field_errors[0]
        : 'An error occurred while processing your request. Please try again later.';

      setError(errorMessage);
    } else {
      setError('An unexpected error occurred. Please try again later.');
    }
  };

  return (
    <Container className="mt-5">
      <h2>Login</h2>
      {error && <Alert variant="danger">{error}</Alert>}
      <Form onSubmit={handleSubmit}>
        <Form.Group className="mb-3" controlId="formUsername">
          <Form.Label>Username</Form.Label>
          <Form.Control
            type="text"
            placeholder="Enter username"
            name="username"
            value={credentials.username}
            onChange={handleChange}
          />
        </Form.Group>

        <Form.Group className="mb-3" controlId="formPassword">
          <Form.Label>Password</Form.Label>
          <Form.Control
            type="password"
            placeholder="Enter password"
            name="password"
            value={credentials.password}
            onChange={handleChange}
          />
        </Form.Group>

        <Button variant="primary" type="submit">
          Login
        </Button>
      </Form>
    </Container>
  );
};

export default LoginForm;

My AuthContext

// AuthContext.js
import { createContext, useContext, useState } from 'react';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [token, setToken] = useState(localStorage.getItem('token') || null);

  const login = (newToken) => {
    setToken(newToken);
    localStorage.setItem('token', newToken);
  };

  const logout = () => {
    setToken(null);
    localStorage.removeItem('token');
  };

  return (
    <AuthContext.Provider value={{ token, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => useContext(AuthContext);

What else am I missing here?

1

There are 1 answers

0
alpha_N1618 On

You can make something like this in your routing folder if you are using react-router-dom

 <Routes>
    <Route>
      {token ? (
        <>
          <Route path="/*" element={<PrivateRoutes />} />
          <Route index element={<Navigate to="/dashboard" />} />
        </>
      ) : (
        <>
          <Route path="auth/*" element={<AuthPage />} />
          <Route path="*" element={<Navigate to="/auth" />} />
        </>
      )}
    </Route>
  </Routes>

This will allow you to have two different route paths one private and one public. If token exists in provider state then private routes will be accessed by the user.