Sessions של התחברות
חלק מהיחידה אימות ואבטחה במסלול ה-Node.js של Coddy. שיעור 5 מתוך 17.
התחברות מחזירה 200, ואז הבקשה הבאה כבר לא זוכרת מי התחבר. הפעלה זוכרת. בעת ההתחברות השרת יוצר מזהה שאף אחד לא יכול לנחש, שומר לאיזה משתמש הוא שייך ושולח אותו כעוגייה. כל בקשה מאוחרת יותר שולחת את המזהה בחזרה, והשרת מחפש אותו.
המזהה חייב להיות אקראי. עוגייה שמכילה את שם המשתמש תאפשר לכל אחד להקליד Cookie: sid=ada ולהיות Ada. randomBytes(24) מספק 192 ביטים אקראיים. הגדירו את העוגייה כ-httpOnly כדי שסקריפטים בדף לא יוכלו לקרוא אותה.
const cartId = randomBytes(24).toString('base64url');
await carts.insertOne({ _id: cartId, items: [] });
res.cookie('cart', cartId, { httpOnly: true });
// בבקשה מאוחרת יותר
const cart = await carts.findOne({ _id: parseCookies(req.get('cookie')).cart });אתגר
קלPOST /loginשומר את{ _id: sid, userId }ב־sessionsומגדיר את קובץ ה־cookiesid, עםhttpOnly, באמצעותrandomBytes(24).toString('base64url').GET /meמחזיר{ username }עבור אותה הפעלה, או 401{ "error": "Log in first" }.
הירשמו, התחברו, שלחו GET /me, ואז בדקו את Data.
נסו בעצמכם
import express from 'express';
import { parseCookies } from './cookies.js';
import { notes, users } from './db.js';
import { hashPassword, verifyPassword } from './passwords.js';
const app = express();
app.use(express.json());
app.post('/signup', async (req, res) => {
const username = String(req.body.username ?? '').trim().toLowerCase();
const password = String(req.body.password ?? '');
if (!username || password.length < 8) {
return res.status(400).json({ error: 'Pick a username and a password of at least 8 characters' });
}
if (await users.findOne({ username })) {
return res.status(409).json({ error: 'That username is taken' });
}
await users.insertOne({ username, passwordHash: await hashPassword(password) });
res.status(201).json({ username });
});
app.post('/login', async (req, res) => {
const username = String(req.body.username ?? '').trim().toLowerCase();
const user = await users.findOne({ username });
if (!user || !(await verifyPassword(String(req.body.password ?? ''), user.passwordHash))) {
return res.status(401).json({ error: 'Wrong username or password' });
}
res.json({ username: user.username });
});
// סופר כמה פעמים הדפדפן הזה שלח בקשת GET אל /visit.
app.get('/visit', (req, res) => {
const cookies = parseCookies(req.get('cookie'));
const visits = Number(cookies.visits ?? 0) + 1;
res.cookie('visits', String(visits));
res.json({ visits });
});
// פתקים. כרגע כל אחד יכול לקרוא ולכתוב אותם.
app.get('/notes', async (req, res) => {
res.json(await notes.find().toArray());
});
app.post('/notes', async (req, res) => {
const note = { text: String(req.body.text ?? '') };
await notes.insertOne(note);
res.status(201).json(note);
});
app.listen(3000, () => {
console.log('Vault is running on port 3000');
});