[[:oktatas:web:back-end_framework:express|< Express]] ====== Express - Azonosítás ====== * **Szerző:** Sallai András * Copyright (c) Sallai András, 2023 * Szerkesztve: 2024 * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC Attribution-Share Alike 4.0 International]] * Web: https://szit.hu ===== Bevezetés ===== Az útvonalak védelmét úgy tudjuk ellátni, ha van felhasználó aki be tud jelentkezni, és sikeres bejelentkezés után kap egy tokent, amivel majd elérheti a védett útvonalakat. Az útválasztóban beállítható, hogy adott útvonalak csak akkor érhetők el, ha visszakapjuk az érvényes tokent. Ehhez egy köztes szoftvert fogunk használni a tokenek ellenőrzésére. A tokeneket sikeres bejelentkezéskor készítjük. A példánkban a jsonwebtoken-t fogjuk használni. A token szerveroldalon keletkezik, de kliens oldalon tároljuk. ===== Felhasználó felvétele ===== ==== User modell ==== A felhasználók kezeléséhez egy User nevű modellben leírjuk a felhasználóról mit tárolunk. const { DataTypes } = require('sequelize') const sequelize = require('../database/mariadb') const User = sequelize.define('User', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false }, email: { type: DataTypes.STRING, allowNull: true }, password: { type: DataTypes.STRING , allowNull: false } }) //A model és az adatbázis szinkronizálása, nem erőltetve. sequelize.sync({ force: false }) module.exports = User ==== AuthController ==== Az Auth kontroller helyett készíthetnék akár egy User kontrollert is, de az Auth névhez jobban illek majd a login() metódus. Telepítsük a bcryptjs csomagot: npm install bcryptjs A bcryptjs a bcrypt JavaScriptre optimalizált változata. Készítsük el az app/controllers/authcontroller.js fájlt: const bcrypt = require('bcryptjs') const User = require('../models/user') const AuthController = { async register(req, res) { var clientError = false; try { if(!req.body.name || !req.body.email || !req.body.password || !req.body.password_confirmation) { clientError = true throw new Error('Error! Bad request data!') } if(req.body.password != req.body.password_confirmation) { clientError = true throw new Error('Error! The two password is not same!') } const user = await User.findOne({ where: { name: req.body.name } }) if(user) { clientError = true throw new Error('Error! User already exists: ' + user.name) } AuthController.tryRegister(req, res) } catch (error) { if (clientError) { res.status(400) }else { res.status(500) } await res.json({ success: false, message: 'Error! User creation failed!', error: error.message }) } }, async tryRegister(req, res) { const user = { name: req.body.name, email: req.body.email, password: bcrypt.hashSync(req.body.password) } await User.create(user) .then( result => { res.status(201) res.json({ succes: true, data: result }) }) } } module.exports = AuthController ==== Routing ==== Írjunk egy új útválasztó sort: const AuthController = require('../controllers/authcontroller') //... router.post('/register', AuthController.register) A teljes kód: const Router = require('express'); const router = Router(); const EmployeeController = require('../controllers/employeecontroller') const AuthController = require('../controllers/authcontroller') router.get('/employees', EmployeeController.index) router.post('/employees', EmployeeController.store) router.put('/employees/:id', EmployeeController.update) router.delete('/employees/:id', EmployeeController.destroy) router.post('/register', AuthController.register) module.exports = router ===== Bejelentkezés ===== ==== APP_KEY ==== Vegyük fel a .env fájlban az APP_KEY tulajdonságot: APP_KEY=3434384383343 Írjunk bele, legalább 32 számot és betűt. ==== Az authcontroller.js-ben ==== const jwt = require('jsonwebtoken') //... async login(req, res) { try { if(!req.body.name || !req.body.password) { res.status(400) throw new Error('Error! Bad name or password!') } const user = await User.findOne({ where: { name: req.body.name } }) if(!user) { res.status(404) throw new Error('Error! User not found!') } var passwordIsValid = await bcrypt.compare( req.body.password, user.dataValues.password ); if(!passwordIsValid) { res.status(401) throw new Error('Error! Password is not valid!') } AuthController.tryLogin(req, res, user) } catch (error) { res.json({ success: false, message: 'Error! The login is failed!', error: error.message }) } }, async tryLogin(req, res, user) { var token = jwt.sign({ id: user.id }, config.app.key, { expiresIn: 86400 //24 óra }) res.status(200).json({ id: user.id, name: user.name, email: user.email, accessToken: token }) } } ==== Útválasztás ==== router.post('/login', AuthController.login) ===== Útvonal védelme ===== ==== Token ellenőrző köztes szoftver ==== const jwt = require("jsonwebtoken"); require('dotenv').config() exports.verifyToken = (req, res, next) => { let authData = req.headers.authorization; if(!authData) { return res.status(403).send({ message: 'No token provided!' }) } let token = authData.split(' ')[1]; jwt.verify(token, process.env.APP_KEY, (err, decoded) => { if(err) { return res.status(401).send({ message: "Unauthorized!" }) } req.userId = decoded.id; next() }) }; ==== Útválasztás ==== const { verifyToken } = require('../middleware/authjwt'); //... router.post('/employees', [verifyToken], EmployeeController.store) Ellenőrzés, például: http post localhost:8000/api/employees name='Verdi Ernő' city='Szeged' -A bearer -a eyJhbG A -a után a token írjuk, ami valójában jóval hosszabb. Állítsuk be az update és delete műveletre is: router.delete('/employees/:id', [verifyToken], employees.destroy); router.put('/employees/:id', [verifyToken], employees.update);