Rute di Balik Login
Termasuk bagian Autentikasi dan Keamanan dalam perjalanan Node.js di Coddy. Pelajaran 6 dari 17.
Setiap rute privat memerlukan pencarian sesi dari GET /me. Jika disalin ke setiap rute, hal ini akan terlupakan di salah satu rute, sehingga rute itu terbuka untuk semua orang. Tulis sekali saja sebagai middleware.
Middleware berjalan sebelum rute. Middleware akan memberikan respons lalu berhenti, atau menaruh apa yang ditemukan pada req dan memanggil next(). Berikan middleware ini ke setiap rute yang memerlukannya, sebelum handler:
function requireAdult(req, res, next) {
if (Number(req.query.age) < 18) {
return res.status(403).json({ error: 'Adults only' });
}
req.adult = true;
next();
}
app.get('/wines', requireAdult, (req, res) => res.json(wines));return itu penting: tanpanya, rute juga akan dijalankan.
Tantangan
Mudah- Tulis
requireUser: kirim 401{ "error": "Log in first" }tanpa sesi yang valid, jika tidak, tetapkanreq.user = { id, username }dan panggilnext(). GET /me,GET /notes, danPOST /notesmenggunakannya. Catatan menyimpanowner: req.user.id, danGET /noteshanya menampilkan catatan milikmu.
Kirim GET /notes saat belum login, lalu login dan tambahkan catatan.
Coba sendiri
import express from 'express';
import { randomBytes } from 'node:crypto';
import { parseCookies } from './cookies.js';
import { notes, sessions, 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' });
}
const sid = randomBytes(24).toString('base64url');
await sessions.insertOne({ _id: sid, userId: user._id, createdAt: new Date() });
res.cookie('sid', sid, { httpOnly: true });
res.json({ username: user.username });
});
app.get('/me', async (req, res) => {
const { sid } = parseCookies(req.get('cookie'));
const session = sid && (await sessions.findOne({ _id: sid }));
if (!session) {
return res.status(401).json({ error: 'Log in first' });
}
const user = await users.findOne({ _id: session.userId });
res.json({ username: user.username });
});
// Menghitung berapa kali browser ini mengakses 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 });
});
// Catatan. Untuk saat ini, siapa saja bisa membaca dan menulis catatan.
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');
});
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Autentikasi dan Keamanan
4Pemilik dan Keamanan
Hanya CatatanmuPeran AdminLatihan sendiri: Playground Express