Tokens verifizieren
Teil des Abschnitts Authentifizierung und Sicherheit der Node.js-Journey von Coddy. Lektion 11 von 17.
Ein API-Client sendet sein Token bei jeder Anfrage in einem Header: Authorization: Bearer <token>. Wenn du es mit decodeJwt ausliest, würdest du jedes beliebige Token akzeptieren, das jemand eingegeben hat. jwtVerify(token, key) berechnet die Signatur mit deinem geheimen Schlüssel neu und löst einen Fehler aus, wenn sie nicht übereinstimmt, wenn das Token abgelaufen ist oder wenn es überhaupt kein JWT ist. Erst nachdem die Funktion zurückgekehrt ist, kannst du payload vertrauen.
async function requireDevice(req, res, next) {
const token = (req.get('authorization') ?? '').replace(/^Bearer /, '');
try {
const { payload } = await jwtVerify(token, deviceKey);
req.device = payload.sub;
} catch {
return res.status(401).json({ error: 'Unknown device' });
}
next();
}Aufgabe
Einfach- Schreibe
requireUser: Überprüfe dasAuthorization: Bearer-Token mitjwtVerifyund setzereq.user = { id, username }anhand seiner Claims oder antworte mit 401{ "error": "Log in first" }. GET /meverwendet es und gibtreq.userzurück.
Sende GET /me ohne Token. Hole dir eines mit POST /token, füge den Header Authorization: Bearer <token> hinzu und sende erneut GET /me. Ändere dann einen Buchstaben des Tokens und sende es noch einmal.
Probier es selbst
import express from 'express';
import { SignJWT, decodeJwt } from 'jose';
import { users } from './db.js';
import { hashPassword, verifyPassword } from './passwords.js';
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
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 });
});
app.post('/token', 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 token = await new SignJWT({ username: user.username })
.setProtectedHeader({ alg: 'HS256' })
.setSubject(user._id.toHexString())
.setIssuedAt()
.setExpirationTime('1h')
.sign(secret);
res.json({ token });
});
// Zeigt den Inhalt eines Tokens an: GET /inspect?token=...
app.get('/inspect', (req, res) => {
try {
res.json(decodeJwt(String(req.query.token ?? '')));
} catch {
res.status(400).json({ error: 'Not a JWT' });
}
});
// Die Admin-Seite. Keiner Angabe darf vertraut werden, bevor ihre Signatur überprüft wurde.
app.get('/admin', (req, res) => {
res.status(403).json({ error: 'Admins only' });
});
app.listen(3000, () => {
console.log('Vault is running on port 3000');
});
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Authentifizierung und Sicherheit
4Eigentümer und Sicherheit
Nur deine NotizenAdmin-Rollen2Sitzungen und Cookies
Mit Cookies merkenLogin-Sitzungen