From ab526cca2af1bb8b8c4b6b80cd15ea443de7189a Mon Sep 17 00:00:00 2001 From: Andrew Trieu Date: Fri, 7 Jul 2023 19:33:54 +0300 Subject: [PATCH] Authentication and authorization --- server/controllers/auth.js | 83 ++++++++++++++++++++++++++++++++++++++ server/index.js | 8 ++++ server/middleware/auth.js | 15 +++++++ server/models/User.js | 45 +++++++++++++++++++++ server/routes/auth.js | 8 ++++ 5 files changed, 159 insertions(+) create mode 100644 server/controllers/auth.js create mode 100644 server/middleware/auth.js create mode 100644 server/models/User.js create mode 100644 server/routes/auth.js diff --git a/server/controllers/auth.js b/server/controllers/auth.js new file mode 100644 index 0000000..e710348 --- /dev/null +++ b/server/controllers/auth.js @@ -0,0 +1,83 @@ +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; +import User from "../models/User.js"; + +/** + * Register a user + */ +export const register = async (req, res) => { + try { + const { + firstName, + lastName, + email, + password, + profilePicturePath, + friends, + location, + description, + } = req.body; + + const salt = await bcrypt.genSalt(10); + const hashedPassword = await bcrypt.hash(password, salt); + + const newUser = new User({ + firstName, + lastName, + email, + password: hashedPassword, + profilePicturePath, + friends, + location, + description, + admin: false, + }); + + const savedUser = await newUser.save(); + res.status(201).json(savedUser); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; + +/** + * Delete a user + */ +export const deleteUser = async (req, res) => { + try { + const user = await User.findById(req.params.id); + try { + await user.delete(); + res.status(200).json({ msg: "User has been deleted" }); + } catch (error) { + res.status; + } + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; + +/** + * Login a user + */ +export const login = async (req, res) => { + try { + const { email, password } = req.body; + + const user = await User.findOne({ email }); + + if (!user) return res.status(404).json({ msg: "User not found" }); + + const validPassword = await bcrypt.compare(password, user.password); + if (!validPassword) return res.status(400).json({ msg: "Wrong password" }); + + const accessToken = jwt.sign( + { id: user._id, admin: user.admin }, + process.env.JWT_SECRET + ); + delete user.password; + res.status(200).json({ accessToken, user }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; diff --git a/server/index.js b/server/index.js index 22864dc..ff697c9 100644 --- a/server/index.js +++ b/server/index.js @@ -8,6 +8,9 @@ import helmet from "helmet"; import morgan from "morgan"; import path from "path"; import { fileURLToPath } from "url"; +import authRoutes from "./routes/auth.js"; +/* Controllers */ +import { register } from "./controllers/auth.js"; /** * Config @@ -38,6 +41,11 @@ const storage = multer.diskStorage({ }); const upload = multer({ storage }); +/** + * Routes + * */ +app.post("/auth/register", upload.single("profilePicture"), register); + /** * Database * */ diff --git a/server/middleware/auth.js b/server/middleware/auth.js new file mode 100644 index 0000000..3ef6202 --- /dev/null +++ b/server/middleware/auth.js @@ -0,0 +1,15 @@ +import jwt from "jsonwebtoken"; + +export const verifyToken = (req, res, next) => { + try { + let token = req.header("Authorization"); + if (!token) return res.status(403).json({ error: "Unauthorized" }); + token = token.split(" ")[1]; + + const verifiedToken = jwt.verify(token, process.env.JWT_SECRET); + req.user = verifiedToken; + next(); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; diff --git a/server/models/User.js b/server/models/User.js new file mode 100644 index 0000000..f41aaf8 --- /dev/null +++ b/server/models/User.js @@ -0,0 +1,45 @@ +import mongoose from "mongoose"; + +const userSchema = mongoose.Schema( + { + firstName: { + type: String, + required: [true, "First name is required"], + min: 3, + max: 20, + }, + lastName: { + type: String, + required: [true, "Last name is required"], + min: 3, + max: 20, + }, + email: { + type: String, + required: [true, "Email is required"], + max: 50, + unique: true, + }, + password: { + type: String, + required: [true, "Password is required"], + min: 6, + }, + profilePicturePath: { + type: String, + default: "", + }, + friends: { + type: Array, + default: [], + }, + location: String, + description: String, + admin: Boolean, + }, + { timestamps: true } +); + +const User = mongoose.model("User", userSchema); + +export default User; diff --git a/server/routes/auth.js b/server/routes/auth.js new file mode 100644 index 0000000..8433bbb --- /dev/null +++ b/server/routes/auth.js @@ -0,0 +1,8 @@ +import express from "express"; +import { login } from "../controllers/auth.js"; + +const router = express.Router(); + +router.post("/login", login); + +export default router;