Authentication and Authorization in django and React project

 ////////////////Login Serializer////////////////////////////////////////

from rest_framework import serializers
from django.contrib.auth import authenticate
from rest_framework_simplejwt.tokens import RefreshToken
class LoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField(write_only=True)

    def validate(self, data):
        username = data.get('username')
        password = data.get('password')

        if username and password:
            user = authenticate(username=username, password=password)
            if user is None:
                raise serializers.ValidationError("Invalid username or password.")
            if not user.is_active:
                raise serializers.ValidationError("This account is inactive.")
        else:
            raise serializers.ValidationError("Must include both 'username' and 'password'.")
       
        # Return the authenticated user
        data['user']=user
        data['is_admin']=user.is_superuser  # Check if the user is an admin
        # print(user.is_superuser)
        return data
    def get_tokens_for_user(self, user):
        refresh = RefreshToken.for_user(user)
        return {
            'refresh': str(refresh),
            'access': str(refresh.access_token),
        }

/////////////////Login View//////////////////////////////////////////////

from rest_framework.response import Response
from .serializers import LoginSerializer
from rest_framework.views import APIView
#login view
class LoginView(APIView):
    def post(self, request):
        serializer = LoginSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.validated_data['user']
            tokens = serializer.get_tokens_for_user(user)
            # print(serializer.validated_data['is_admin'])
            return Response({
                    'access':tokens['access'],
                    'refresh':tokens['refresh'],
                    'isAdmin':serializer.validated_data['is_admin'],
                })
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

/////////////////Logout View//////////////////////////////////////////////

#logout Views
class CustomLogout(APIView):  
   def post(self,request):
       logout(request)
       return Response(status=status.HTTP_200_OK)

///////////////////React for login///////////////////////////////

//Login.js
import React, { useState,useContext,useEffect } from "react";
import axios from 'axios';
import { useNavigate,Navigate} from 'react-router-dom';
import { LoginContext } from "../contextapi/LoginContext";
const Login = () => {
  const navigate = useNavigate();
  const{loggedUser,setLoggedUser}=useContext(LoginContext)
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    const loginData = { username, password };
    try {
        const  response = await axios.post('http://localhost:8000/starthere/', loginData);
        // Save the access and refresh tokens in local storage or a cookie
        localStorage.setItem('access_token', response.data.access);
        localStorage.setItem('refresh_token', response.data.refresh);
        if(response.data.isAdmin)
        {
          setLoggedUser("Admin")
        }
        navigate("/home");
    } catch (error) {
        setError("Login failed. Please check your credentials.");
        console.error("Error during login:", error);
    }
  };

  return (
    <div className="flex justify-center items-center h-screen bg-slate-50">
      <div className="bg-slate-100 p-8 rounded-lg shadow-lg max-w-md w-full">
        <h2 className="text-2xl font-semibold mb-6 text-center">Login</h2>{error && <p style={{color: 'red'}}>{error}</p>}
        <form onSubmit={handleSubmit}>
          <div className="mb-4">
            <label className="block text-gray-700 mb-2">Username</label>
            <input
              type="text"
              className="w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-400"
              value={username}
              onChange={(e) => setUsername(e.target.value)}
              required
            />
          </div>
          <div className="mb-4">
            <label className="block text-gray-700 mb-2">Password</label>
            <input
              type="password"
              className="w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-400"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
          </div>
          <button type="submit" className="w-full bg-blue-500 text-white py-2 rounded-md hover:bg-blue-600 transition duration-300">
            Login
          </button>
        </form>
      </div>
    </div>
  );
};

export default Login;


///////////////////////React for logout///////////////////////////////

// Logout.js
import React from 'react';
import { useNavigate,Navigate } from 'react-router-dom';
const Logout = () => {
    const navigate = useNavigate();
    const handleLogout = async () => {
        try {
            const response = await fetch('http://localhost:8000/closefrom/', {
                method: 'POST'});
            if (response.ok) {
                // Clear user data from local storage or context
                localStorage.removeItem('user'); // Example: remove user data
                localStorage.removeItem('access_token');
                localStorage.removeItem('refresh_token');
                 console.log("Logout success");
                    setLoggedUser(null)
                 navigate("/login")
            } else {
                console.error('Logout failed');
            }
        } catch (error) {
            console.error('Error during logout:', error);
        }
    };

    return (
        <button onClick={handleLogout}>Logout</button>
    );
};

export default Logout;

/////////////////contexapi////////////////////////////

//LoginContext.js
import React, { createContext, useState,useEffect } from 'react';

// Create LoginContext
export const LoginContext = createContext({});

// Create a provider component
export const LoginProvider = ({ children }) => {
  // Load the initial state from localStorage or default to null
      const [loggedUser, setLoggedUser] = useState(() => {
        const storedUser = localStorage.getItem('loggedUser');
        return storedUser ? JSON.parse(storedUser) : null;
    });
 // Update localStorage whenever loggedUser changes
 useEffect(() => {
        if (loggedUser) {
            localStorage.setItem('loggedUser', JSON.stringify(loggedUser));
        } else {
            localStorage.removeItem('loggedUser');
        }
      }, [loggedUser]);

  return (
    <LoginContext.Provider value={{ loggedUser, setLoggedUser }}>
      {children}
    </LoginContext.Provider>
  );
};


//////////////index.js//////////////////////////////////////

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {LoginProvider} from './contextapi/LoginContext';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <React.StrictMode>
     <LoginProvider>
          <App />
     </LoginProvider>    
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

////////////////app.js///////////////////////////////////

import React, { useEffect } from "react";
import { BrowserRouter as Router, Routes, Route,Navigate } from 'react-router-dom';
import Admin from './component/Admin'
import Login from "./component/Login";
import Home from './component/Home';
import './index.css'
function App() {
  const isAuthenticated = !!localStorage.getItem('access_token'); // Check if the user is authenticated
  useEffect(()=>{
    const isAuthenticated = !!localStorage.getItem('access_token'); // Check if the user is authenticated
  },[localStorage])
  return(
   
          <Router>
              <Routes>
                <Route path="/login" element={<Login />} />
                 <Route path="/home" element={isAuthenticated ? <Home /> : <Navigate to="/login" />} />
                  <Route path="/admin" element={isAuthenticated ? <Admin /> : <Navigate to="/login" />} /> {/* Admin route */}
                  <Route path="*" element={<Navigate to="/login" />} />
              </Routes>
          </Router>
  );
}
export default App;

////////////////home.js///////////////////////////////

import Navbar from "./Navbar";
import Bill from "./Bill";
function Home(){
return(
    <>
        <div>
            <Navbar />
            <Bill/>
        </div>

    </>
 )
}

export default Home;

///////////////////Navbar.js////////////////////////////

Show admin link only user is admin

import { useState,useContext } from "react";
import { LoginContext } from "../contextapi/LoginContext";
import Logout from './Logout'
import logo from '../images/watch.png'
import { Link } from "react-router-dom"; // Import Link from react-router-dom
function Navbar() {
    const {loggedUser}=useContext(LoginContext)
    const [isOpen, setIsOpen] = useState(false);
    const toggleMenu = () => {
        setIsOpen(!isOpen);
    };
    return (
        <nav className="bg-white border-gray-200 dark:bg-gray-900">
            <div className="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
                <a href="#" className="flex items-center space-x-3 rtl:space-x-reverse">
                    <img src={logo} className="h-8" alt="Time Logo" />
                    <span className="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">WorkSchedule</span>
                </a>
                <button
                    onClick={toggleMenu}
                    data-collapse-toggle="navbar-default"
                    type="button"
                    className="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
                    aria-controls="navbar-default"
                    aria-expanded={isOpen ? "true" : "false"}
                >
                    <span className="sr-only">Open main menu</span>
                    <svg className="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
                        <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M1 1h15M1 7h15M1 13h15" />
                    </svg>
                </button>
                <div className={`${isOpen ? "block" : "hidden"} w-full md:block md:w-auto`} id="navbar-default">
                    <ul className="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
                        <li>
                            <Link to="#" className="block py-2 px-3 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 dark:text-white md:dark:text-blue-500" aria-current="page">Home</Link>
                        </li>
                        <li>
                            <Link to="#" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">About</Link>
                        </li>
                        <li>
                            <Link to="#" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Services</Link>
                        </li>
                        <li>
                            {loggedUser==="Admin" && (
                                     <li>
                                            <Link to="/admin" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Admin</Link>
                                    </li>)}
                        </li>
                        <li>
                            <span className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent"><Logout/></span>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    );
}

export default Navbar;



Comments

Popular posts from this blog

Basic Web Design with HTML and CSS

Project Web Design Assignment