Tokenları Doğrulama
Coddy'nin Node.js Journey'sinin Kimlik Doğrulama ve Güvenlik bölümünün bir parçası. Ders 11 / 17.
Bir API istemcisi belirtecini her istekte bir başlıkta gönderir: Authorization: Bearer <token>. decodeJwt ile okumak, herhangi birinin yazdığı herhangi bir belirteci kabul eder. jwtVerify(token, key) gizli anahtarınızla imzayı yeniden hesaplar ve eşleşmediğinde, belirtecin süresi dolduğunda veya belirteç hiç JWT olmadığında hata fırlatır. Ancak bu işlev sonuç döndürdükten sonra payload değerine güvenebilirsiniz.
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();
}Görev
KolayrequireUseryaz:Authorization: BearerbelirtecinijwtVerifyile doğrula ve taleplerindenreq.user = { id, username }değerini ayarla ya da 401 yanıtı ver:{ "error": "Log in first" }.GET /mebunu kullanır vereq.useryanıtını verir.
GET /me isteğini belirteç olmadan gönder. POST /token ile bir tane al, Authorization: Bearer <token> başlığını ekle ve GET /me isteğini yeniden gönder. Ardından belirtecin bir harfini değiştir ve bir kez daha gönder.
Kendin dene
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 });
});
// Bir token’ın içeriğini gösterir: 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' });
}
});
// Yönetici sayfası. İmzası doğrulanmadan hiçbir beyana güvenilemez.
app.get('/admin', (req, res) => {
res.status(403).json({ error: 'Admins only' });
});
app.listen(3000, () => {
console.log('Vault is running on port 3000');
});
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.