Menu
CoddyTech

Oturumu Kapatma

Coddy'nin Node.js Journey'sinin Kimlik Doğrulama ve Güvenlik bölümünün bir parçası. Ders 7 / 17.

Çerezi temizlemek yalnızca tarayıcıdan kimliği unutmasını ister. İster başka bir cihazdan ister çalınmış bir çerezden olsun, onu kopyalayan herkes hâlâ çalışan bir anahtara sahiptir. Oturum kapatılırken sunucudaki oturum silinmelidir.

res.clearCookie(name) tarayıcıya bir çerezi silmesini söyler. 204 No Content durumu, işlemin başarılı olduğu ve geri gönderilecek bir şey olmadığı anlamına gelir: res.status(204).end().

İşte kullanıcıyı aynı anda tüm cihazlarda oturumdan çıkaran ilgili bir rota:

app.post('/logout-everywhere', requireUser, async (req, res) => {
    await sessions.deleteMany({ userId: new ObjectId(req.user.id) });
    res.clearCookie('sid');
    res.status(204).end();
});
challenge icon

Görev

Kolay
  • POST /logout, sid çerezinin oturumunu siler, çerezi temizler ve 204 yanıtı verir.
  • Oturum yoksa da 204 yanıtı verir.

Giriş yap, POST /logout gönder, ardından GET /me gönder.

Kendin dene

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 });
});

// Oturum çerezinin kullanıcısını bulur veya 401 yanıtı verir.
async function requireUser(req, res, next) {
    const { sid } = parseCookies(req.get('cookie'));
    const session = sid && (await sessions.findOne({ _id: sid }));
    const user = session && (await users.findOne({ _id: session.userId }));
    if (!user) {
        return res.status(401).json({ error: 'Log in first' });
    }
    req.user = { id: user._id.toHexString(), username: user.username };
    next();
}

app.get('/me', requireUser, (req, res) => {
    res.json({ username: req.user.username });
});

// Bu tarayıcının GET /visit isteğini kaç kez yaptığını sayar.
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 });
});

// Notlar: Her kullanıcı yalnızca kendi notlarını okur ve yazar.
app.get('/notes', requireUser, async (req, res) => {
    res.json(await notes.find({ owner: req.user.id }).toArray());
});

app.post('/notes', requireUser, async (req, res) => {
    const note = { owner: req.user.id, 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');
});

Kimlik Doğrulama ve Güvenlik bölümündeki tüm dersler