Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
R
R24-152
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
19
Issues
19
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tharaka it19975696
R24-152
Commits
186b4e79
Commit
186b4e79
authored
8 months ago
by
Tharaka it19975696
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Authentication module improvements and logout function
parent
bc901804
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
163 additions
and
130 deletions
+163
-130
server/index.js
server/index.js
+62
-65
server/middleware/authenticateToken.js
server/middleware/authenticateToken.js
+4
-5
src/components/App.js
src/components/App.js
+28
-14
src/components/Navbar.js
src/components/Navbar.js
+40
-30
src/components/RegisterPage.js
src/components/RegisterPage.js
+29
-16
No files found.
server/index.js
View file @
186b4e79
...
@@ -4,8 +4,9 @@ const cors = require('cors');
...
@@ -4,8 +4,9 @@ const cors = require('cors');
const
{
PrismaClient
}
=
require
(
'
@prisma/client
'
);
const
{
PrismaClient
}
=
require
(
'
@prisma/client
'
);
const
{
hashPassword
,
verifyPassword
}
=
require
(
'
./utils/authHelpers
'
);
const
{
hashPassword
,
verifyPassword
}
=
require
(
'
./utils/authHelpers
'
);
const
jwt
=
require
(
'
jsonwebtoken
'
);
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
app
=
express
();
const
prisma
=
new
PrismaClient
();
const
prisma
=
new
PrismaClient
();
...
@@ -21,99 +22,95 @@ if (!JWT_SECRET) {
...
@@ -21,99 +22,95 @@ if (!JWT_SECRET) {
process
.
exit
(
1
);
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
// Registration endpoint for a student
app
.
post
(
'
/register/student
'
,
async
(
req
,
res
)
=>
{
app
.
post
(
'
/register/student
'
,
async
(
req
,
res
)
=>
{
try
{
try
{
const
{
username
,
password
}
=
req
.
body
;
const
{
username
,
password
}
=
req
.
body
;
// Check if username is already taken
const
existingStudent
=
await
prisma
.
student
.
findUnique
({
const
existingStudent
=
await
prisma
.
student
.
findUnique
({
where
:
{
username
:
username
}
where
:
{
username
}
});
});
if
(
existingStudent
)
{
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
hashedPassword
=
await
hashPassword
(
password
);
const
student
=
await
prisma
.
student
.
create
({
const
student
=
await
prisma
.
student
.
create
({
data
:
{
username
,
password
:
hashedPassword
}
data
:
{
username
,
password
:
hashedPassword
}
});
});
// Exclude password from the response for security reasons
const
{
password
:
_
,
...
studentWithoutPassword
}
=
student
;
const
token
=
createToken
(
student
.
id
,
'
student
'
)
;
res
.
status
(
201
).
json
(
studentWithoutPassword
);
res
.
status
(
201
).
json
(
{
token
});
// Send the token in the response
}
catch
(
error
)
{
}
catch
(
error
)
{
res
.
status
(
500
).
json
({
message
:
'
Error registering student
'
,
error
:
error
.
message
}
);
res
.
status
(
500
).
send
(
'
Error registering student
'
);
}
}
});
});
// Registration endpoint for a teacher
// Registration endpoint for a teacher
app
.
post
(
'
/register/teacher
'
,
async
(
req
,
res
)
=>
{
app
.
post
(
'
/register/teacher
'
,
async
(
req
,
res
)
=>
{
try
{
try
{
const
{
username
,
password
}
=
req
.
body
;
const
{
username
,
password
}
=
req
.
body
;
// Check if username is already taken
const
existingTeacher
=
await
prisma
.
teacher
.
findUnique
({
const
existingTeacher
=
await
prisma
.
teacher
.
findUnique
({
where
:
{
username
}
where
:
{
username
}
});
});
if
(
existingTeacher
)
{
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
hashedPassword
=
await
hashPassword
(
password
);
const
teacher
=
await
prisma
.
teacher
.
create
({
const
teacher
=
await
prisma
.
teacher
.
create
({
data
:
{
username
,
password
:
hashedPassword
}
data
:
{
username
,
password
:
hashedPassword
}
});
});
// Exclude password from the response for security reasons
const
{
password
:
_
,
...
teacherWithoutPassword
}
=
teacher
;
const
token
=
createToken
(
teacher
.
id
,
'
teacher
'
)
;
res
.
status
(
201
).
json
(
teacherWithoutPassword
);
res
.
status
(
201
).
json
(
{
token
});
// Send the token in the response
}
catch
(
error
)
{
}
catch
(
error
)
{
res
.
status
(
500
).
json
({
message
:
'
Error registering teacher
'
,
error
:
error
.
message
}
);
res
.
status
(
500
).
send
(
'
Error registering teacher
'
);
}
}
});
});
// Login endpoint for a student
// Login endpoint for a student
app
.
post
(
'
/login/student
'
,
async
(
req
,
res
)
=>
{
app
.
post
(
'
/login/student
'
,
async
(
req
,
res
)
=>
{
try
{
try
{
const
{
username
,
password
}
=
req
.
body
;
const
{
username
,
password
}
=
req
.
body
;
const
student
=
await
prisma
.
student
.
findUnique
({
const
student
=
await
prisma
.
student
.
findUnique
({
where
:
{
username
}
where
:
{
username
}
});
});
if
(
!
student
||
!
(
await
verifyPassword
(
password
,
student
.
password
)))
{
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
'
});
const
token
=
createToken
(
student
.
id
,
'
student
'
);
res
.
json
({
token
});
res
.
json
({
token
});
// Send the token in the response
}
catch
(
error
)
{
}
catch
(
error
)
{
res
.
status
(
500
).
json
({
message
:
'
Error logging in
'
,
error
:
error
.
message
});
res
.
status
(
500
).
send
(
'
Error logging in
'
);
}
});
// 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
isPasswordValid
=
await
verifyPassword
(
password
,
teacher
.
password
);
// Login endpoint for teachers
if
(
!
isPasswordValid
)
{
app
.
post
(
'
/login/teacher
'
,
async
(
req
,
res
)
=>
{
return
res
.
status
(
401
).
json
({
message
:
'
Invalid username or password
'
});
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
=
createToken
(
teacher
.
id
,
'
teacher
'
);
const
token
=
jwt
.
sign
({
teacherId
:
teacher
.
teacherID
},
process
.
env
.
JWT_SECRET
,
{
expiresIn
:
'
1h
'
});
res
.
json
({
token
});
// Send the token in the response
res
.
json
({
token
});
}
catch
(
error
)
{
}
catch
(
err
)
{
res
.
status
(
500
).
send
(
'
Error logging in
'
);
res
.
status
(
500
).
json
({
message
:
'
Something went wrong
'
,
error
:
err
.
message
});
}
}
});
});
/* Commented out due to repeated Logic Conflicts
// Start the server
// Example of a protected route
const
PORT
=
process
.
env
.
PORT
||
5000
;
app.get('/protected-route', authenticateToken, (req, res) => {
app
.
listen
(
PORT
,
()
=>
{
res.json({ message: 'This is a protected route' });
console
.
log
(
`Server running on port
${
PORT
}
`
);
});
});
*/
\ No newline at end of file
// Start the server
const
PORT
=
process
.
env
.
PORT
||
5000
;
app
.
listen
(
PORT
,
()
=>
{
console
.
log
(
`Server running on port
${
PORT
}
`
);
});
This diff is collapsed.
Click to expand it.
server/middleware/authenticateToken.js
View file @
186b4e79
...
@@ -2,14 +2,13 @@
...
@@ -2,14 +2,13 @@
const
jwt
=
require
(
'
jsonwebtoken
'
);
const
jwt
=
require
(
'
jsonwebtoken
'
);
function
authenticateToken
(
req
,
res
,
next
)
{
function
authenticateToken
(
req
,
res
,
next
)
{
const
authHeader
=
req
.
headers
[
'
authorization
'
];
const
token
=
req
.
headers
[
'
authorization
'
]?.
split
(
'
'
)[
1
];
// Using optional chaining
const
token
=
authHeader
&&
authHeader
.
split
(
'
'
)[
1
];
if
(
!
token
)
return
res
.
sendStatus
(
401
);
// Using negation (!) for clarity
if
(
token
==
null
)
return
res
.
sendStatus
(
401
);
jwt
.
verify
(
token
,
process
.
env
.
JWT_SECRET
,
(
err
,
user
)
=>
{
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
;
req
.
user
=
user
;
next
();
next
();
// Token is valid, proceed to the next middleware
});
});
}
}
...
...
This diff is collapsed.
Click to expand it.
src/components/App.js
View file @
186b4e79
// React core
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
import
React
,
{
useState
,
useEffect
}
from
'
react
'
;
// React Router DOM for routing
import
{
BrowserRouter
as
Router
,
Routes
,
Route
,
Navigate
}
from
'
react-router-dom
'
;
import
{
BrowserRouter
as
Router
,
Routes
,
Route
,
Navigate
}
from
'
react-router-dom
'
;
// Components
import
Home
from
'
./Home
'
;
import
Home
from
'
./Home
'
;
import
About
from
'
./About
'
;
import
About
from
'
./About
'
;
import
Insights
from
'
./Insights
'
;
import
Insights
from
'
./Insights
'
;
...
@@ -11,13 +16,15 @@ function App() {
...
@@ -11,13 +16,15 @@ function App() {
const
[
isLoggedIn
,
setIsLoggedIn
]
=
useState
(
false
);
const
[
isLoggedIn
,
setIsLoggedIn
]
=
useState
(
false
);
useEffect
(()
=>
{
useEffect
(()
=>
{
// Assume token is stored in localStorage after successful login/registration
const
token
=
localStorage
.
getItem
(
'
token
'
);
const
token
=
localStorage
.
getItem
(
'
token
'
);
if
(
token
)
{
setIsLoggedIn
(
!!
token
);
setIsLoggedIn
(
true
);
}
},
[]);
},
[]);
const
handleLogout
=
()
=>
{
localStorage
.
removeItem
(
'
token
'
);
setIsLoggedIn
(
false
);
};
const
handleLoginSuccess
=
()
=>
{
const
handleLoginSuccess
=
()
=>
{
setIsLoggedIn
(
true
);
setIsLoggedIn
(
true
);
};
};
...
@@ -28,20 +35,27 @@ function App() {
...
@@ -28,20 +35,27 @@ function App() {
return
(
return
(
<
Router
>
<
Router
>
<
Navbar
/>
<
Navbar
isLoggedIn
=
{
isLoggedIn
}
onLogout
=
{
handleLogout
}
/
>
<
Routes
>
<
Routes
>
{
/* Redirect to home if user is already logged in */
}
<
Route
path
=
"
/login
"
element
=
{
<
Route
path
=
"
/login
"
element
=
{
!
isLoggedIn
?
<
LoginPage
onLoginSuccess
=
{
handleLoginSuccess
}
/> : <Navigate replace to="/
home
"
/>} />
!
isLoggedIn
?
(
<Route path=
"
/
register
"
element={!isLoggedIn ? <RegisterPage onRegistrationSuccess={handleRegistrationSuccess} /> : <Navigate replace to=
"
/
home
"
/>} />
<
LoginPage
onLoginSuccess
=
{
handleLoginSuccess
}
/
>
)
:
(
{/* Protected routes that require user to be logged in */}
<
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
=
"
/about
"
element
=
{
isLoggedIn
?
<
About
/>
:
<
Navigate
replace
to
=
"
/login
"
/>
}
/
>
<
Route
path
=
"
/insights
"
element
=
{
isLoggedIn
?
<
Insights
/>
:
<
Navigate
replace
to
=
"
/login
"
/>
}
/
>
<
Route
path
=
"
/insights
"
element
=
{
isLoggedIn
?
<
Insights
/>
:
<
Navigate
replace
to
=
"
/login
"
/>
}
/
>
<
Route
path
=
"
/home
"
element
=
{
isLoggedIn
?
<
Home
/>
:
<
Navigate
replace
to
=
"
/login
"
/>
}
/
>
<
Route
path
=
"
/home
"
element
=
{
isLoggedIn
?
<
Home
/>
:
<
Navigate
replace
to
=
"
/login
"
/>
}
/
>
<
Route
path
=
"
/
"
element
=
{
<
Navigate
replace
to
=
{
isLoggedIn
?
"
/home
"
:
"
/login
"
}
/>} /
>
{/* Default route */}
<
Route
path
=
"
*
"
element
=
{
<
Navigate
replace
to
=
{
isLoggedIn
?
"
/home
"
:
"
/login
"
}
/>} /
>
<Route path=
"
/
"
element={<Navigate replace to={isLoggedIn ?
"
/
home
"
:
"
/
register
"
} />} />
<Route path=
"
*
"
element={<Navigate replace to={isLoggedIn ?
"
/
home
"
:
"
/
register
"
} />} />
<
/Routes
>
<
/Routes
>
<
/Router
>
<
/Router
>
);
);
...
...
This diff is collapsed.
Click to expand it.
src/components/Navbar.js
View file @
186b4e79
// Navbar.js
// Navbar.js
import
React
from
'
react
'
;
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
})
=>
const
activeLinkStyle
=
({
isActive
})
=>
isActive
?
'
text-blue-500
'
:
'
text-white
'
;
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
(
return
(
<
nav
className
=
"
bg-gray-800 p-4
"
>
<
nav
className
=
"
bg-gray-800 p-4
"
>
<
ul
className
=
"
flex justify-start items-center space-x-4
"
>
<
ul
className
=
"
flex justify-between items-center space-x-4
"
>
<
li
>
<
div
className
=
"
flex space-x-4
"
>
<
NavLink
<
li
>
to
=
"
/
"
<
NavLink
to
=
"
/
"
className
=
{
activeLinkStyle
}
aria
-
label
=
"
Home
"
>
className
=
{
activeLinkStyle
}
Home
aria
-
label
=
"
Home
"
<
/NavLink
>
>
<
/li
>
Home
<
li
>
<
/NavLink
>
<
NavLink
to
=
"
/about
"
className
=
{
activeLinkStyle
}
aria
-
label
=
"
About
"
>
<
/li
>
About
<
li
>
<
/NavLink
>
<
NavLink
<
/li
>
to
=
"
/about
"
<
li
>
className
=
{
activeLinkStyle
}
<
NavLink
to
=
"
/insights
"
className
=
{
activeLinkStyle
}
aria
-
label
=
"
Insights
"
>
aria
-
label
=
"
About
"
Insights
>
<
/NavLink
>
About
<
/li
>
<
/NavLink
>
<
/div
>
<
/li
>
{
isLoggedIn
&&
(
<
li
>
<
li
>
<
NavLink
<
button
onClick
=
{
logout
}
className
=
"
text-white hover:text-red-500 transition duration-300
"
>
to
=
"
/insights
"
Logout
className
=
{
activeLinkStyle
}
<
/button
>
aria
-
label
=
"
Insights
"
<
/li
>
>
)}
Insights
<
/NavLink
>
<
/li
>
<
/ul
>
<
/ul
>
<
/nav
>
<
/nav
>
);
);
...
...
This diff is collapsed.
Click to expand it.
src/components/RegisterPage.js
View file @
186b4e79
// src/components/RegisterPage.js
// src/components/RegisterPage.js
import
React
,
{
useState
}
from
'
react
'
;
import
React
,
{
useState
}
from
'
react
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
{
Link
,
useNavigate
}
from
'
react-router-dom
'
;
import
{
registerStudent
,
registerTeacher
}
from
'
../api/api
'
;
// A
djusted import path
import
{
registerStudent
,
registerTeacher
}
from
'
../api/api
'
;
// A
ssuming these are API calls returning promises
const
RegisterPage
=
()
=>
{
const
RegisterPage
=
()
=>
{
const
[
userData
,
setUserData
]
=
useState
({
const
[
userData
,
setUserData
]
=
useState
({
username
:
''
,
username
:
''
,
password
:
''
,
password
:
''
,
role
:
'
student
'
,
// default role
role
:
'
student
'
,
// default role
});
});
const
navigate
=
useNavigate
();
const
handleChange
=
(
e
)
=>
{
const
handleChange
=
(
e
)
=>
{
setUserData
({
...
userData
,
[
e
.
target
.
name
]:
e
.
target
.
value
});
setUserData
({
...
userData
,
[
e
.
target
.
name
]:
e
.
target
.
value
});
};
};
const
handleSubmit
=
async
(
e
)
=>
{
const
handleSubmit
=
async
(
e
)
=>
{
e
.
preventDefault
();
e
.
preventDefault
();
try
{
try
{
if
(
userData
.
role
===
'
student
'
)
{
let
token
;
await
registerStudent
({
username
:
userData
.
username
,
password
:
userData
.
password
});
if
(
userData
.
role
===
'
student
'
)
{
}
else
{
const
response
=
await
registerStudent
({
username
:
userData
.
username
,
password
:
userData
.
password
});
await
registerTeacher
({
username
:
userData
.
username
,
password
:
userData
.
password
});
token
=
response
.
token
;
}
}
else
{
alert
(
'
Registration successful
'
);
const
response
=
await
registerTeacher
({
username
:
userData
.
username
,
password
:
userData
.
password
});
}
catch
(
error
)
{
token
=
response
.
token
;
alert
(
error
.
message
);
}
}
};
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
(
return
(
<
div
className
=
"
flex items-center justify-center h-screen bg-gray-200
"
>
<
div
className
=
"
flex items-center justify-center h-screen bg-gray-200
"
>
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment