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
Post a Comment