-
Notifications
You must be signed in to change notification settings - Fork 446
project auth #328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
project auth #328
Changes from all commits
6f7d3e5
0a45fc6
62aa656
9e2f656
60b7040
699a711
9dc6f09
08e279e
9186e2e
0d6fcfa
c880c3f
f23da3a
c0a3ba4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import jwt from "jsonwebtoken" | ||
| import User from "../model/User.js" | ||
|
|
||
| const authenticateUser = async (req, res, next) => { | ||
| try { | ||
| const token = req.header("Authorization").replace("Bearer ", "") | ||
| const decoded = jwt.verify(token, process.env.JWT_SECRET) | ||
| console.log('Token:', token); | ||
| console.log('Dekrypterad token:', decoded); | ||
| const user = await User.findOne({ _id: decoded.userId }) | ||
| if (!user) { | ||
| throw new Error() | ||
| } | ||
| req.user = user | ||
| next() | ||
| } catch (error) { | ||
| res.status(401).json({ error: "Please authenticate" }) | ||
| } | ||
| } | ||
|
|
||
| export default authenticateUser | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import mongoose from 'mongoose'; | ||
|
|
||
| const thoughtSchema = new mongoose.Schema({ | ||
| text: { type: String, required: true }, | ||
| user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true } | ||
| }); | ||
|
|
||
| const Thought = mongoose.model('Thought', thoughtSchema); | ||
|
|
||
| export default Thought; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import mongoose from 'mongoose'; | ||
| import bcrypt from 'bcryptjs'; | ||
|
|
||
| const userSchema = new mongoose.Schema({ | ||
| username: { type: String, required: true, unique: true }, | ||
| password: { type: String, required: true } | ||
| }); | ||
|
|
||
| userSchema.pre('save', async function(next) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In your routes you're using arrow functions, try to be consistent with that throughout the whole code base |
||
| const user = this; | ||
| if (!user.isModified('password')) return next(); | ||
| try { | ||
| const hash = await bcrypt.hash(user.password, 10); | ||
| user.password = hash; | ||
| next(); | ||
| } catch (error) { | ||
| return next(error); | ||
| } | ||
| }); | ||
|
|
||
| const User = mongoose.model('User', userSchema); | ||
|
|
||
| export default User; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import express from "express" | ||
| import bcrypt from "bcryptjs" | ||
| import jwt from "jsonwebtoken" | ||
| import User from "../model/User.js" | ||
| import authenticateUser from "../middleware/authenticateUser.js" | ||
| import Thought from "../model/Thought.js" | ||
|
|
||
| const authRouter = express.Router() | ||
|
|
||
| authRouter.post("/signup", async (req, res) => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Endpoints are most often named nouns in plural, so instead of signup and login, it could be POST /users and POST /sessions |
||
| try { | ||
| const { username, password } = req.body | ||
| const user = new User({ username, password: password }) | ||
| await user.save() | ||
| res.status(201).json({ message: "User registered successfully" }) | ||
| } catch (error) { | ||
| res.status(500).json({ error: error.message }) | ||
| } | ||
| }) | ||
|
|
||
| authRouter.get("/signup", async (req, res) => { | ||
| try { | ||
| const users = await User.find() | ||
| res.status(200).json(users) | ||
| } catch (error) { | ||
| res.status(500).json({ error: error.message }) | ||
| } | ||
| }) | ||
|
Comment on lines
+21
to
+28
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the thought behind this route? And how about security? |
||
|
|
||
| authRouter.post("/login", async (req, res) => { | ||
| try { | ||
| const { username, password } = req.body | ||
| console.log(username) | ||
| console.log(password) | ||
|
Comment on lines
+33
to
+34
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove logs |
||
| const user = await User.findOne({ username }) | ||
| console.log(user) | ||
| console.log("Inkommande lösenord:", password) | ||
| console.log("Hashat lösenord i databasen:", user.password) | ||
| if (!user) { | ||
| return res.status(401).json({ error: "Invalid username or password" }) | ||
| } | ||
| const isPasswordValid = await bcrypt.compare(password, user.password) | ||
| console.log(isPasswordValid) | ||
| if (!isPasswordValid) { | ||
| return res.status(401).json({ error: "Invalid username or password" }) | ||
| } | ||
| const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET) | ||
| console.log("Genererat JWT-token:", token) | ||
| res.status(200).json({ token }) | ||
| } catch (error) { | ||
| res.status(500).json({ error: error.message }) | ||
| } | ||
| }) | ||
|
|
||
| authRouter.get("/thoughts", authenticateUser, async (req, res) => { | ||
| try { | ||
| const userId = req.user._id | ||
| const userThoughts = await Thought.find({ user: userId }) | ||
|
|
||
| res.status(200).json(userThoughts) | ||
| } catch (error) { | ||
| res.status(500).json({ error: error.message }) | ||
| } | ||
| }) | ||
|
|
||
| authRouter.post("/thoughts", authenticateUser, async (req, res) => { | ||
| try { | ||
| const { thought } = req.body | ||
| const userId = req.user._id | ||
| const newThought = new Thought({ text: thought, user: userId }) | ||
| await newThought.save() | ||
| res.status(201).json({ message: "Thought saved successfully" }) | ||
| } catch (error) { | ||
| res.status(500).json({ error: error.message }) | ||
| } | ||
| }) | ||
|
|
||
| export default authRouter | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,33 @@ | ||
| import cors from "cors"; | ||
| import express from "express"; | ||
| import mongoose from "mongoose"; | ||
| import express from "express" | ||
| import mongoose from "mongoose" | ||
| import cors from "cors" | ||
| import listEndpoints from "express-list-endpoints" | ||
| import authRouter from "./routes/Auth.js" | ||
|
|
||
| const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; | ||
| mongoose.connect(mongoUrl); | ||
| mongoose.Promise = Promise; | ||
| const app = express() | ||
| const port = process.env.SERVER_PORT || 3001 | ||
|
|
||
| // Defines the port the app will run on. Defaults to 8080, but can be overridden | ||
| // when starting the server. Example command to overwrite PORT env variable value: | ||
| // PORT=9000 npm start | ||
| const port = process.env.PORT || 8080; | ||
| const app = express(); | ||
| app.use(cors()) | ||
| app.use(express.json()) | ||
|
|
||
| // Add middlewares to enable cors and json body parsing | ||
| app.use(cors()); | ||
| app.use(express.json()); | ||
| mongoose.connect(`mongodb://${process.env.DB_HOST}:${process.env.DB_PORT}`, { | ||
| dbName: process.env.DB_NAME, | ||
| user: process.env.DB_USER, | ||
| pass: process.env.DB_PASS, | ||
| }) | ||
| const db = mongoose.connection | ||
| db.on("error", console.error.bind(console, "Anslutningsfel:")) | ||
| db.once("open", () => { | ||
| console.log("Ansluten till databasen") | ||
| }) | ||
|
Comment on lines
+18
to
+22
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! Just remember that even logs and comments should be in English |
||
|
|
||
| // Start defining your routes here | ||
| app.get("/", (req, res) => { | ||
| res.send("Hello Technigo!"); | ||
| }); | ||
| const endpoints = listEndpoints(app) | ||
| res.json(endpoints) | ||
| }) | ||
|
|
||
| app.use(authRouter) | ||
|
|
||
| // Start the server | ||
| app.listen(port, () => { | ||
| console.log(`Server running on http://localhost:${port}`); | ||
| }); | ||
| console.log(`Chattservern lyssnar på port ${port}`) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import crypto from "crypto" | ||
|
|
||
| const jwtSecret = crypto.randomBytes(32).toString("hex") | ||
| console.log(jwtSecret) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,23 @@ | ||
| export const App = () => { | ||
| return <div>Find me in src/app.jsx!</div>; | ||
| }; | ||
| import { BrowserRouter as Router, Route, Routes } from "react-router-dom" | ||
| import Register from "./components/Register" | ||
| import Login from "./components/Login" | ||
| import Thoughts from "./components/Thoughts" | ||
| import Home from "./components/Home" | ||
| import { AuthProvider } from "./context/AuthContext" | ||
|
|
||
| function App() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, arrow function |
||
| return ( | ||
| <AuthProvider> | ||
| <Router> | ||
| <Routes> | ||
| <Route path="/" element={<Home />} /> | ||
| <Route path="/register" element={<Register />} /> | ||
| <Route path="/login" element={<Login />} /> | ||
| <Route path="/thoughts" element={<Thoughts />} /> | ||
| </Routes> | ||
| </Router> | ||
| </AuthProvider> | ||
| ) | ||
| } | ||
|
|
||
| export default App | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { Link } from "react-router-dom"; | ||
|
|
||
| const Home = () => { | ||
| return ( | ||
| <div> | ||
| <h2>Welcome to the Home Page</h2> | ||
| <p>Please select an option:</p> | ||
| <div> | ||
| <Link to="/register"> | ||
| <button>Register</button> | ||
| </Link> | ||
| <Link to="/login"> | ||
| <button>Login</button> | ||
| </Link> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Home; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import { useState, useContext, useEffect } from "react" | ||
| import axios from "axios" | ||
| import { useNavigate } from "react-router-dom" | ||
| import { AuthContext } from "../context/AuthContext" | ||
| import { getUserIdFromToken } from "../context/authHelpers" | ||
|
|
||
| const Login = () => { | ||
| const [username, setUsername] = useState("") | ||
| const [password, setPassword] = useState("") | ||
| const { login } = useContext(AuthContext) | ||
| const navigate = useNavigate() | ||
|
|
||
| useEffect(() => { | ||
| const token = localStorage.getItem("token") | ||
| if (token && getUserIdFromToken(token)) { | ||
| navigate("/thoughts") | ||
| } | ||
| }, [navigate]) | ||
|
|
||
| const handleSubmit = async (e) => { | ||
| e.preventDefault() | ||
| try { | ||
| console.log("Starting login process...") | ||
|
|
||
| const userResponse = await axios.get( | ||
| `https://project-auth-7ju7.onrender.com/signup?username=${username}` | ||
| ) | ||
| console.log("User response:", userResponse.data) | ||
|
|
||
| if (!userResponse.data || !userResponse.data.length) { | ||
| alert("User does not exist. Please register first.") | ||
| return | ||
| } | ||
|
|
||
| console.log("User exists. Proceeding with login...") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alerts are enough, no need for logs |
||
|
|
||
| const response = await axios.post( | ||
| "https://project-auth-7ju7.onrender.com/login", | ||
| { | ||
| username, | ||
| password, | ||
| } | ||
| ) | ||
|
|
||
| console.log("Login response:", response.data) | ||
|
|
||
| localStorage.setItem("token", response.data.token) | ||
|
|
||
|
|
||
| login(response.data.token) | ||
|
|
||
| console.log("Login successful. Navigating to /thoughts...") | ||
| navigate("/thoughts") | ||
| } catch (error) { | ||
| console.error("Login failed:", error) | ||
| alert("Login failed") | ||
| } | ||
| } | ||
|
|
||
| return ( | ||
| <form onSubmit={handleSubmit}> | ||
| <h2>Login</h2> | ||
| <input | ||
| type="text" | ||
| placeholder="Username" | ||
| value={username} | ||
| onChange={(e) => setUsername(e.target.value)} | ||
| /> | ||
| <input | ||
| type="password" | ||
| placeholder="Password" | ||
| value={password} | ||
| onChange={(e) => setPassword(e.target.value)} | ||
| /> | ||
| <button type="submit">Login</button> | ||
| </form> | ||
| ) | ||
| } | ||
|
|
||
| export default Login | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fun that you tried out jwt 👍