Commit 186b4e79 authored by Tharaka it19975696's avatar Tharaka it19975696 🎧

Authentication module improvements and logout function

parent bc901804
......@@ -4,8 +4,9 @@ const cors = require('cors');
const { PrismaClient } = require('@prisma/client');
const { hashPassword, verifyPassword } = require('./utils/authHelpers');
const jwt = require('jsonwebtoken');
// Uncomment the line below if you're using the authenticateToken middleware
// const { authenticateToken } = require('./middleware/authenticateToken');
// Uncomment if we decide to use the authenticateToken middleware
//const { authenticateToken } = require('./middleware/authenticateToken');
const app = express();
const prisma = new PrismaClient();
......@@ -21,99 +22,95 @@ if (!JWT_SECRET) {
process.exit(1);
}
// Helper function to create a JWT token
const createToken = (userId, role) => {
return jwt.sign(
{ userId, role },
JWT_SECRET,
{ expiresIn: '1h' }
);
};
// Registration endpoint for a student
app.post('/register/student', async (req, res) => {
try {
const { username, password } = req.body;
// Check if username is already taken
const existingStudent = await prisma.student.findUnique({
where: { username: username }
where: { username }
});
if (existingStudent) {
return res.status(409).json({ message: 'Username already exists' });
return res.status(409).send('Username already exists');
}
const hashedPassword = await hashPassword(password);
const student = await prisma.student.create({
data: { username, password: hashedPassword }
});
// Exclude password from the response for security reasons
const { password: _, ...studentWithoutPassword } = student;
res.status(201).json(studentWithoutPassword);
} catch (error) {
res.status(500).json({ message: 'Error registering student', error: error.message });
}
});
// Registration endpoint for a teacher
app.post('/register/teacher', async (req, res) => {
try {
const token = createToken(student.id, 'student');
res.status(201).json({ token }); // Send the token in the response
} catch (error) {
res.status(500).send('Error registering student');
}
});
// Registration endpoint for a teacher
app.post('/register/teacher', async (req, res) => {
try {
const { username, password } = req.body;
// Check if username is already taken
const existingTeacher = await prisma.teacher.findUnique({
where: { username }
});
if (existingTeacher) {
return res.status(409).json({ message: 'Username already exists' });
return res.status(409).send('Username already exists');
}
const hashedPassword = await hashPassword(password);
const teacher = await prisma.teacher.create({
data: { username, password: hashedPassword }
});
// Exclude password from the response for security reasons
const { password: _, ...teacherWithoutPassword } = teacher;
res.status(201).json(teacherWithoutPassword);
} catch (error) {
res.status(500).json({ message: 'Error registering teacher', error: error.message });
}
});
// Login endpoint for a student
app.post('/login/student', async (req, res) => {
try {
const token = createToken(teacher.id, 'teacher');
res.status(201).json({ token }); // Send the token in the response
} catch (error) {
res.status(500).send('Error registering teacher');
}
});
// Login endpoint for a student
app.post('/login/student', async (req, res) => {
try {
const { username, password } = req.body;
const student = await prisma.student.findUnique({
where: { username }
});
if (!student || !(await verifyPassword(password, student.password))) {
return res.status(401).json({ message: 'Invalid credentials' });
return res.status(401).send('Invalid credentials');
}
const token = jwt.sign({ studentId: student.studentID }, 'YOUR_SECRET_KEY', { expiresIn: '1h' });
res.json({ token });
} catch (error) {
res.status(500).json({ message: 'Error logging in', error: error.message });
}
});
// Similar login endpoint for teachers
app.post('/login/teacher', async (req, res) => {
const { username, password } = req.body;
try {
const teacher = await prisma.teacher.findUnique({ where: { username } });
if (!teacher) {
return res.status(401).json({ message: 'Invalid username or password' });
const token = createToken(student.id, 'student');
res.json({ token }); // Send the token in the response
} catch (error) {
res.status(500).send('Error logging in');
}
});
const isPasswordValid = await verifyPassword(password, teacher.password);
if (!isPasswordValid) {
return res.status(401).json({ message: 'Invalid username or password' });
// Login endpoint for teachers
app.post('/login/teacher', async (req, res) => {
try {
const { username, password } = req.body;
const teacher = await prisma.teacher.findUnique({
where: { username }
});
if (!teacher || !(await verifyPassword(password, teacher.password))) {
return res.status(401).send('Invalid credentials');
}
const token = jwt.sign({ teacherId: teacher.teacherID }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({ token });
} catch (err) {
res.status(500).json({ message: 'Something went wrong', error: err.message });
const token = createToken(teacher.id, 'teacher');
res.json({ token }); // Send the token in the response
} catch (error) {
res.status(500).send('Error logging in');
}
});
/* Commented out due to repeated Logic Conflicts
// Example of a protected route
app.get('/protected-route', authenticateToken, (req, res) => {
res.json({ message: 'This is a protected route' });
});
*/
// Start the server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// Start the server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
\ No newline at end of file
......@@ -2,14 +2,13 @@
const jwt = require('jsonwebtoken');
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
const token = req.headers['authorization']?.split(' ')[1]; // Using optional chaining
if (!token) return res.sendStatus(401); // Using negation (!) for clarity
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
if (err) return res.sendStatus(403); // Forbidden if there's an error
req.user = user;
next();
next(); // Token is valid, proceed to the next middleware
});
}
......
// React core
import React, { useState, useEffect } from 'react';
// React Router DOM for routing
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
// Components
import Home from './Home';
import About from './About';
import Insights from './Insights';
......@@ -11,13 +16,15 @@ function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
// Assume token is stored in localStorage after successful login/registration
const token = localStorage.getItem('token');
if (token) {
setIsLoggedIn(true);
}
setIsLoggedIn(!!token);
}, []);
const handleLogout = () => {
localStorage.removeItem('token');
setIsLoggedIn(false);
};
const handleLoginSuccess = () => {
setIsLoggedIn(true);
};
......@@ -28,20 +35,27 @@ function App() {
return (
<Router>
<Navbar />
<Navbar isLoggedIn={isLoggedIn} onLogout={handleLogout} />
<Routes>
{/* Redirect to home if user is already logged in */}
<Route path="/login" element={!isLoggedIn ? <LoginPage onLoginSuccess={handleLoginSuccess} /> : <Navigate replace to="/home" />} />
<Route path="/register" element={!isLoggedIn ? <RegisterPage onRegistrationSuccess={handleRegistrationSuccess} /> : <Navigate replace to="/home" />} />
{/* Protected routes that require user to be logged in */}
<Route path="/login" element={
!isLoggedIn ? (
<LoginPage onLoginSuccess={handleLoginSuccess} />
) : (
<Navigate replace to="/home" />
)
} />
<Route path="/register" element={
!isLoggedIn ? (
<RegisterPage onRegistrationSuccess={handleRegistrationSuccess} />
) : (
<Navigate replace to="/home" />
)
} />
<Route path="/about" element={isLoggedIn ? <About /> : <Navigate replace to="/login" />} />
<Route path="/insights" element={isLoggedIn ? <Insights /> : <Navigate replace to="/login" />} />
<Route path="/home" element={isLoggedIn ? <Home /> : <Navigate replace to="/login" />} />
{/* Default route */}
<Route path="/" element={<Navigate replace to={isLoggedIn ? "/home" : "/register"} />} />
<Route path="*" element={<Navigate replace to={isLoggedIn ? "/home" : "/register"} />} />
<Route path="/" element={<Navigate replace to={isLoggedIn ? "/home" : "/login"} />} />
<Route path="*" element={<Navigate replace to={isLoggedIn ? "/home" : "/login"} />} />
</Routes>
</Router>
);
......
// Navbar.js
import React from 'react';
import { NavLink } from 'react-router-dom';
import { NavLink, useNavigate } from 'react-router-dom';
const Navbar = ({ isLoggedIn, onLogout }) => {
const navigate = useNavigate();
const Navbar = () => {
const activeLinkStyle = ({ isActive }) =>
isActive ? 'text-blue-500' : 'text-white';
const logout = () => {
// Clear the user token and any other relevant data
localStorage.removeItem('token');
// Call the onLogout prop to update the App state
onLogout();
// Redirect to the login page
navigate('/login');
};
return (
<nav className="bg-gray-800 p-4">
<ul className="flex justify-start items-center space-x-4">
<li>
<NavLink
to="/"
className={activeLinkStyle}
aria-label="Home"
>
Home
</NavLink>
</li>
<li>
<NavLink
to="/about"
className={activeLinkStyle}
aria-label="About"
>
About
</NavLink>
</li>
<li>
<NavLink
to="/insights"
className={activeLinkStyle}
aria-label="Insights"
>
Insights
</NavLink>
</li>
<ul className="flex justify-between items-center space-x-4">
<div className="flex space-x-4">
<li>
<NavLink to="/" className={activeLinkStyle} aria-label="Home">
Home
</NavLink>
</li>
<li>
<NavLink to="/about" className={activeLinkStyle} aria-label="About">
About
</NavLink>
</li>
<li>
<NavLink to="/insights" className={activeLinkStyle} aria-label="Insights">
Insights
</NavLink>
</li>
</div>
{isLoggedIn && (
<li>
<button onClick={logout} className="text-white hover:text-red-500 transition duration-300">
Logout
</button>
</li>
)}
</ul>
</nav>
);
......
// src/components/RegisterPage.js
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { registerStudent, registerTeacher } from '../api/api'; // Adjusted import path
import { Link, useNavigate } from 'react-router-dom';
import { registerStudent, registerTeacher } from '../api/api'; // Assuming these are API calls returning promises
const RegisterPage = () => {
const RegisterPage = () => {
const [userData, setUserData] = useState({
username: '',
password: '',
role: 'student', // default role
});
const navigate = useNavigate();
const handleChange = (e) => {
setUserData({ ...userData, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
if (userData.role === 'student') {
await registerStudent({ username: userData.username, password: userData.password });
} else {
await registerTeacher({ username: userData.username, password: userData.password });
}
alert('Registration successful');
} catch (error) {
alert(error.message);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
let token;
if (userData.role === 'student') {
const response = await registerStudent({ username: userData.username, password: userData.password });
token = response.token;
} else {
const response = await registerTeacher({ username: userData.username, password: userData.password });
token = response.token;
}
if (token) {
console.log("Token received:", token); // Log for debugging
localStorage.setItem('token', token); // Store the token
navigate('/'); // Redirect to the homepage
} else {
console.error("No token received");
alert('Registration successful but no token received');
}
} catch (error) {
console.error("Registration failed:", error);
alert(error.message);
}
};
return (
<div className="flex items-center justify-center h-screen bg-gray-200">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment