Menandatangani Token
Termasuk bagian Autentikasi dan Keamanan dalam perjalanan Node.js di Coddy. Pelajaran 10 dari 17.
Sebuah token hanya bernilai jika tidak ada orang lain yang bisa membuatnya. jose menandatanganinya dengan HS256: HMAC dari header dan payload, yang menggunakan kunci rahasia yang hanya diketahui server.
Kunci rahasia berasal dari variabel lingkungan, process.env.JWT_SECRET, bukan dari kode: kode dibagikan, disalin, dan di-commit. Pelajaran ini menetapkan JWT_SECRET untukmu. jose memerlukan kunci rahasia itu dalam bentuk byte.
const key = new TextEncoder().encode(process.env.INVITE_SECRET);
const invite = await new SignJWT({ room: 'design' })
.setProtectedHeader({ alg: 'HS256' })
.setSubject(guestId)
.setIssuedAt()
.setExpirationTime('2d')
.sign(key);setSubject menerima teks, dan setExpirationTime menerima rentang waktu seperti '30m' atau '2d'.
Tantangan
MudahPOST /tokendengan{ username, password }memberikan jawaban{ token }: HS256, ditandatangani denganJWT_SECRET, klaimusername, subject berupa id pengguna dalam bentuk teks, kedaluwarsa dalam 1 jam.- Login yang salah memberikan jawaban 401
{ "error": "Wrong username or password" }.
Daftar, dapatkan token, lalu tempelkan ke GET /inspect?token=.
Coba sendiri
import express from 'express';
import { decodeJwt } from 'jose';
import { 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 });
});
// Menampilkan isi token: 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' });
}
});
// Halaman admin. Jangan percaya klaim apa pun sebelum tanda tangannya diperiksa.
app.get('/admin', (req, res) => {
res.status(403).json({ error: 'Admins only' });
});
app.listen(3000, () => {
console.log('Vault is running on port 3000');
});
Semua pelajaran di Autentikasi dan Keamanan
4Pemilik dan Keamanan
Hanya CatatanmuPeran AdminLatihan sendiri: Playground Express