Jak implementovat JWT ověřování v Node.js API

  • Autentizace pomocí JWT umožňuje bezstavová, škálovatelná a snadno udržovatelná API v Node.js.
  • Node.js, Express, MongoDB, jsonwebtoken a bcryptjs tvoří technický základ zabezpečeného API.
  • Tok je založen na registraci uživatelů, vydávání tokenů po přihlášení a ochraně tras pomocí middlewaru.
  • Správná správa utajení, platnosti tokenů a šifrování hesel je klíčem k bezpečnosti.

JWT ověřování v Node.js API

Při vývoji API dnes již zabezpečení a řízení přístupu nejsou volitelnými doplňky, ale povinnými. Každá rozumně seriózní aplikace musí rozlišovat, kteří uživatelé se mohou přihlásit, co mohou dělat a jak dlouho. A zde přichází na řadu ověřování založené na JSON Web Tokenu (JWT) – systém, který je široce používán díky snadné integraci a vynikající škálovatelnosti.

V tomto článku se krok za krokem a velmi podrobně dozvíte, jak implementovat JWT ověřování v API pomocí Node.js a Express . Probereme přesně, co JWT je, proč se tak široce používá v moderních API, jaké knihovny potřebujete a jak vytvořit kompletní tok pro registraci, přihlášení a ochranu směrování od nuly. Také probereme osvědčené postupy a užitečné tipy, které zajistí bezpečnost vaší implementace.

Co přesně je JSON webový token (JWT)?

JWT je, zjednodušeně řečeno, standardní formát pro odesílání informací, jako je JSON, v kompaktní a digitálně podepsané podobě . Je definován ve specifikaci RFC 7519 a byl navržen tak, aby se dal snadno přenášet po síti, například v záhlavích HTTP nebo dokonce v URL.

Výhodou JWT je, že server může důvěřovat datům obsaženým v tokenu, protože je podepsán . Tento podpis je generován pomocí sdíleného tajného klíče (ve schématech HMAC) nebo pomocí páru veřejného/soukromého klíče (algoritmy jako RSA nebo ECDSA). Pokud server dokáže ověřit podpis, ví, že obsah tokenu nebyl zmanipulován.

V praxi se JWT skládá ze tří částí kódovaných v Base64 oddělených tečkami: záhlaví, datové části a podpisu. Záhlaví mimo jiné specifikuje algoritmus podpisu. Datová část je místo, kam ukládáte potřebné informace (například ID uživatele), a podpis zaručuje integritu celé sekvence.

Pracovní postup CI/CD s akcemi GitHubu
Související článek:
Jak nastavit tok CI/CD s akcemi GitHubu od nuly

Výhody použití JWT k ověřování v API

Důvod, proč JWT vidíme všude, je ten, že umožňuje model bezstavového ověřování . To znamená, že server nemusí ukládat relace do paměti ani do databáze: jednoduše ověří token při každém požadavku a pokud je správný, udělí přístup.

Tento bezstavový přístup výrazně zjednodušuje horizontální škálování vašeho API . Pokud máte za load balancerem více serverů, nemusíte mezi nimi sdílet informace o relaci. Pokud všechny znají stejný tajný klíč pro ověření tokenů, kterýkoli z nich může konzistentně reagovat na jakýkoli požadavek.

JWT jsou navíc velmi kompaktní a snadno se přenášejí . Mohou být odesílány v autorizační hlavičce, v souboru cookie nebo v případě potřeby i v parametrech dotazu. Díky tomu jsou obzvláště vhodné pro jednostránkové aplikace (SPA) nebo mobilní klienty, kteří využívají vaše API.

Další velmi důležitou výhodou je, že do tokenu můžete zahrnout relevantní uživatelské informace (role, oprávnění, ID atd.) pro rozhodování, aniž byste museli s každým požadavkem provádět další dotaz do databáze. Je však nejlepší tuto funkci nepřehánět a vyhnout se zahrnutí citlivých dat nebo více informací, než je nutné.

Jak funguje proces ověřování s JWT

Typický proces integrace JWT do Node.js API se řídí poměrně jasnou sekvencí, které je třeba dobře porozumět před psaním jakéhokoli kódu. Zjednodušeně řečeno, životní cyklus tokenu v aplikaci je obvykle následující:

  1. Uživatel odešle své přihlašovací údaje (obvykle uživatelské jméno a heslo) k serveru prostřednictvím přihlašovacího koncového bodu.
  2. Server ověří tyto přihlašovací údaje. s databází (nebo jiným úložným systémem). Pokud se neshodují, je požadavek odmítnut s příslušnou chybou.
  3. Pokud se vše sečte, server Generuje JWT s nezbytnými uživatelskými informacemi (například vaše ID) a podepíše jej tajným klíčem nebo soukromým klíčem nakonfigurovaným pro danou službu.
  4. Tento token se vrátí klientovi, který může uložte jej do localStorage, sessionStorage nebo do souboru cookiev závislosti na bezpečnostní strategii, kterou chcete dodržovat.
  5. Od té chvíle, v každé žádosti o chráněné zdroje, klient odešle JWT na server, obvykle v hlavičce HTTP Authorization ve formátu: Authorization: Bearer <token>.
  6. Server obdrží token a Ověřte jejich podpis a případně i datum platnostiPokud je token správný, požadavek je zpracován; v opačném případě je vrácena chyba 401 nebo 403.
  7. Když platnost tokenu vyprší nebo se stane neplatným, server odmítá požadavky a klient se musí znovu ověřit, aby získal nový token.

Tento tok má obrovskou výhodu v tom, že jakmile je token vydán, server se již nemusí starat o stav relace , pokud je trvání a obsah JWT důvěryhodný.

Předpoklady pro vytvoření JWT API s Node.js

Než se ponoříme do samotného API, je důležité si ujasnit, jaké nástroje a závislosti budete ve svém vývojovém prostředí potřebovat. Minimální seznam, který je třeba pro tento typ implementace dodržovat, je obvykle:

  • Node.js nainstalovaný na vašem počítači, protože to bude spouštěcí prostředí pro celý backend.
  • Expresní, framework Node.js, který vám usnadní vytváření tras a middlewaru.
  • Pošťák nebo nespavost (nebo jakéhokoli jiného HTTP klienta) k otestování koncových bodů API, aniž byste zatím potřebovali frontend.
  • MongoDB jako NoSQL databáze, spolu s Mongoose pro definování modelů a schémat, v případě, že chcete snadno uchovávat uživatele.
  • Specifické balíčky pro ověřování, například jsonwebtoken pro vydávání a ověřování tokenů, bcryptjs pro šifrování hesel a dotenv pro zpracování proměnných prostředí.

S touto sadou nástrojů budete mít více než slušné prostředí pro nastavení REST API s JWT ověřováním v Node.js a budete ho moci rozšiřovat bez větších komplikací.

Vytvoření a inicializace projektu Node.js

Prvním technickým krokem bude vytvoření pracovního adresáře a vygenerování souboru package.json , kde budou registrovány závislosti vašeho projektu. Z terminálu můžete začít něčím velmi podobným následujícímu:

mkdir jwt-auth-api
cd jwt-auth-api
npm init -y

Jakmile je projekt inicializován, je čas nainstalovat hlavní závislosti pro naše API. Typická kombinace může být:

npm install express mongoose jsonwebtoken bcryptjs dotenv

Tím se do vašeho projektu přidá framework Express, Mongoose ODM pro MongoDB, knihovna jsonwebtoken, která bude zpracovávat podepisování a ověřování tokenů, bcryptjs pro bezpečné šifrování hesel a dotenv pro správu citlivých proměnných v souboru prostředí.

Základní struktura souborů pro API

JWT ověřování v Node.js API

Velmi jednoduchá (ale funkční) organizace vašeho projektu by mohla vypadat takto, aby hlavní soubor a datové modely byly dobře odděleny:

jwt-auth-api/
.env
app.js
models/
User.js

Soubor .env bude použit k uložení tajného klíče pro podepisování tokenu a jakékoli další konfigurace, kterou nechcete nahrávat do repozitáře. Do tohoto souboru můžete vložit například:

JWT_SECRET=un_secreto_muy_seguro_y_largo

Myšlenka je taková Nikdy nezobrazujte tento klíč ve zdrojovém kódu přímo, zejména pokud se chystáte nahrát projekt do vzdálené správy verzí. dotenv se postará o načtení těchto proměnných a jejich zpřístupnění vám v process.env.

Definování uživatelského modelu pomocí Mongoose

Pro registraci uživatelů v databázi potřebujete model, který definuje Jaká pole bude mít každý uživatelský dokumentTypický příklad v models/User.js Mohlo by to být něco takového:

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const UserSchema = new mongoose.Schema({
uživatelské_jméno: { typ: Řetězec, povinné: true, jedinečné: true },
heslo: { typ: Řetězec, povinné: true }
});

UserSchema.pre('uložit', asynchronní funkce (další) {
pokud (!this.isModified('heslo')) vrátí další();
this.password = await bcrypt.hash(this.password, 10);
další();
});

module.exports = mongoose.model('Uživatel', SchémaUživatele);

Toto schéma používá operaci před uložením (hook pre('save')) , která detekuje, zda se pole hesla změnilo. Pokud ano, je heslo zašifrováno pomocí bcrypt se zadaným počtem kol hashování (v tomto příkladu 10). Tím se zabrání ukládání hesel v prostém textu, což je v jakémkoli produkčním prostředí zcela nepřijatelné.

Pak jednoduše exportujete uživatelský model, abyste ho mohli použít v hlavním souboru a kdekoli jinde v aplikaci, kde ho potřebujete. Tento vzorec umožňuje zachovat datovou logiku zapouzdřenou v modelech a nemíchat ji s trasami.

Konfigurace expresního serveru a připojení k MongoDB

Jádro vašeho API bude v app.jsZde nastavíte HTTP server, připojíte se k databázi a definujete koncové body pro ověřování klíčů. Velmi běžná kostra by mohla vypadat takto, s několika opravami chaotického pseudokódu, který jste viděli:

const express = require('express');
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const dotenv = require('dotenv');
const User = require('./models/User');

dotenv.config();

const app = express();
použití aplikace(express.json());

mongoose.connect('mongodb://localhost/jwt-auth', {
použitíNewUrlParser: true,
useUnifiedTopology: true
});

Tato počáteční konfigurace načte všechny potřebné závislosti , povolí podporu JSON v tělech požadavků a naváže připojení k MongoDB pomocí výchozí lokální adresy URL. V reálném prostředí by tato adresa URL mohla být také uložena v proměnné prostředí pro oddělení vývoje, testování a produkce.

Koncový bod pro registraci nového uživatele

Další blok funkcí umožní uživateli registrovat se v systému vytvořením nového dokumentu v kolekci uživatelů. Typický registrační koncový bod může vypadat takto:

Domovská stránka vývojářů, Visual Studio Code a Git
Související článek:
Kompletní průvodce k funkci arrow v JavaScriptu

app.post('/register', async (req, res) => {
try {
const { username, password } = req.body;

const existujícíUživatel = await Uživatel.findOne({ uživatelské_jméno });
pokud (existujícíUživatel) {
return res.status(400).json({ zpráva: 'Uživatel již existuje' });
}

const uživatel = nový Uživatel({ uživatelské jméno, heslo });
čeká na uživatele.uložit();

res.status(201).json({ id: user.id, username: user.username });
} catch (chyba) {
res.status(500).json({ zpráva: 'Chyba při registraci uživatele' });
}
});

Zde se z těla požadavku extrahuje uživatelské jméno a heslo, zkontroluje se, zda je uživatelské jméno již obsazené, a pokud je k dispozici, vytvoří se nový uživatel. Šifrování je řešeno hookem ` pre('save')` nakonfigurovaným v modelu , takže se v tomto okamžiku nemusíte obávat přímého volání `bcrypt`.

Přihlašovací koncový bod a vydání tokenu JWT

Dalším krokem je povolit existujícímu uživateli ověření a přijetí jeho JWT tokenu . Za tímto účelem vytvoříte přihlašovací koncový bod, kde se ověřují přihlašovací údaje a pokud jsou správné, podepíše se token s potřebnými informacemi.

app.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
const user = await User.findOne({ username });

pokud (!uživatel) {
vrátit res.status(401).json({ zpráva: 'Neplatné přihlašovací údaje' });
}

const isMatch = await bcrypt.compare(heslo, uživatel.heslo);
pokud (!isMatch) {
vrátit res.status(401).json({ zpráva: 'Neplatné přihlašovací údaje' });
}

const token = jwt.sign(
{ id: user.id },
process.env.JWT_SECRET,
{ expirujeIn: '1h' }
);

res.json({token});
} catch (chyba) {
res.status(500).json({ zpráva: 'Chyba při přihlašování' });
}
});

Funkce jwt.sign() Přijímá tři argumenty: objekt obsahující informace, které mají být zahrnuty v tokenu, tajný klíč a objekt možností. V tomto případě Doba expirace 1 hodina používání nemovitosti expiresInTímto způsobem token nebude platný donekonečna a uživatel se bude muset po uplynutí této doby znovu ověřit.

Pole, které zahrnete do datové části (id: user._idToto bude identifikátor, který budete používat v chráněných trasách k identifikaci uživatele odesílajícího požadavek. Můžete například přidat roli uživatele, pokud chcete spravovat složitější oprávnění.

Middleware pro ochranu tras pomocí JWT

Pouhý token není příliš užitečný, pokud ve svém API explicitně nechráníte určité trasy . Za tímto účelem se obvykle vytváří middleware, který ověřuje JWT u každého požadavku na tyto citlivé koncové body. Jednoduchý příklad middlewaru by mohl být tento:

function authMiddleware(req, res, next) {
const authHeader = req.headers.authorization;

pokud (!authHeader || !authHeader.startsWith('Nositel')) {
return res.status(401).json({ zpráva: 'Token nebyl poskytnut' });
}

const token = authHeader.split(' ');

Snaž se {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = dekódováno;
další();
} catch (chyba) {
return res.status(401).json({ zpráva: 'Neplatný nebo vypršelý token' });
}
}

Tento middleware kontroluje, zda hlavička Authorization existuje a zda má správný formát, extrahuje token a ověří jej pomocí jwt.verify() A pokud všechno dobře dopadne, připojit dekódovaná data k objektu req aby zbytek logiky mohl určit identitu uživatele. Pokud je token neplatný nebo jeho platnost vypršela, vrátí se chyba 401.

Jakmile je middleware definován, můžete jej použít na libovolnou trasu, kterou chcete chránit. Například:

app.get('/perfil', authMiddleware, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (error) {
res.status(500).json({ message: 'Error al obtener el perfil' });
}
});

S tímto vzorem bude jakákoli trasa, kterou přidáte za authMiddleware , omezena na uživatele, kteří ve svém požadavku předloží platný token.

Přímé použití jsonwebtokenu k generování a ověřování tokenů

Kromě integrace s Expressem je užitečné vidět, jak dvě klíčové funkce knihovny jsonwebtoken fungují izolovaně , protože mohou být užitečné ve skriptech, testech nebo pomocných nástrojích.

První je jwt.sign()který je zodpovědný za vytvoření nového tokenu z datové části, tajného kódu a volitelně sady možností. Obecný příklad by mohl vypadat takto:

const jwt = require('jsonwebtoken');

const token = jwt.sign(
{ id: user.id },
'váš-tajný-klíč',
{ expirujeIn: '1h' }
);

Druhá je jwt.verify()který obdrží token a stejný klíč použitý k podpisu. Pokud se vše shoduje, vrátí dekódovaná data; jinak vyvolá chybu, kterou můžete zachytit a vhodně ošetřit:

try {
const decodificado = jwt.verify(token, 'tu-clave-secreta');
console.log(decodificado.id);
} catch (err) {
console.error('Token no válido');
}

Pochopení fungování těchto dvou volání vám pomůže zvládnout proces vytváření a ověřování tokenů a ladit problémy s ověřováním ve vašem API nebo v klientech, kteří vaše služby využívají.

Spuštění a testování serveru pomocí externích nástrojů

Jakmile máte vše propojeno (modely, koncové body, middleware a připojení k databázi), zbývá už jen spustit Express server a začít testovat API . Základní proces spuštění obvykle zahrnuje něco jako:

app.listen(3000, () => {
console.log('Servidor funcionando en el puerto 3000');
});

Odtud můžete použít nástroje Postman, Insomnia nebo podobné k odesílání HTTP požadavků na koncové body registrace, přihlášení a chráněné trasy . Typický testovací tok může vypadat takto:

  • Odeslat požadavek POST na /register s uživatelským jménem a heslem na těle.
  • Ověřte, zda byl uživatel vytvořen a zda byl vrácen nějaký typ potvrzení.
  • Vytvořit příspěvek /login se stejnými pověřovacími listinami a obdržet token v odpovědi.
  • Zkopírujte tento token a použijte ho v hlavičce autorizace k volání chráněné trasy, například /perfilověření, zda server přijme danou informaci a vrátí očekávaná data.

Celý tento proces umožňuje ověřit, zda se tok ověřování JWT chová konzistentně od začátku do konce a zda server reaguje správně v závislosti na platnosti nebo vypršení platnosti tokenu.

Jak povolit JavaScript na telefonu Android
Související článek:
Jak povolit JavaScript na telefonu Android

S touto strukturou máte nyní robustní, škálovatelný a snadno udržovatelný systém ověřování JWT v Node.js a Expressu. Nyní můžete doladit bezpečnostní detaily, přidat role, obnovovat tokeny nebo implementovat jakoukoli další funkci, kterou vaše API potřebuje k připravení k produkčnímu prostředí. Sdílejte tyto informace a pomozte ostatním povolit ověřování JWT pomocí Node.js.


Přidat jako preferovaný zdroj v Googlu