У меня было чертовски много времени с паспортом и jwt. Итак, вот что я понял, что мне нужно сделать, чтобы получить req.user в своих маршрутах. Я, конечно, знал, что мне нужно промежуточное ПО, но какое???
// middleware to test user authentication and set in req.user function verifyUser(req, res, next) { passport.authenticate('jwt', { session: false }, (err, user, info) => { if (err || !user) { return res.status(400).json({ message: info.message }); } req.user = user; next() })(req, res, next); }
И затем в моих маршрутах:
app.use("/api/invoices", verifyUser, invoices);
Просто чтобы охватить все основы, мой файл конфигурации паспорта выглядит так:
const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; const mongoose = require('mongoose'); const User = require('../models/User'); const keys = require('../config/keys'); const options = {}; options.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); options.secretOrKey = keys.secretOrKey; module.exports = passport => { passport.use(new JwtStrategy(options, (payload, done) => { User.findById(payload.id) .then(user => { if (user) { return done(null, user); } else { return done(null, false); } }) .catch(err => console.log(err)) })); };
и мой файл server.js:
const mongoose = require('mongoose'); const express = require("express"); const app = express(); const path = require('path'); const morgan = require('morgan'); const db = require('./config/keys').mongoURI; mongoose .connect(db, { useNewUrlParser: true }) .then(() => console.log("Connected to MongoDB successfully")) .catch(err => console.log(err)); const bodyParser = require('body-parser'); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); // setup logger app.use(morgan('dev')); const passport = require('passport'); app.use(passport.initialize()); require('./config/passport')(passport); // setup static folder for frontend app.use(express.static( `${__dirname}/frontend/build`)); // router routes const users = require("./routes/api/users"); const invoices = require("./routes/api/invoices"); const clients = require("./routes/api/clients"); const subs = require("./routes/api/subscriptions"); // middleware to test user authentication and attach user as req.user function verifyUser(req, res, next) { passport.authenticate('jwt', { session: false }, (err, user, info) => { if (err || !user) { return res.status(400).json({ message: info.message }); } req.user = user; next() })(req, res, next); } app.get("/", (req, res) => res.send("")); app.use("/api/users", users); app.use("/api/invoices", verifyUser, invoices); app.use("/api/clients", verifyUser, clients); app.use("/api/subscriptions", verifyUser, subs); // serve up index.html for frontend app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '/frontend/build/index.html')); }); const port = process.env.PORT || 5000; app.listen(port, () => console.log(`Server is running on port ${port}`));
И мои маршруты входа и регистрации:
const express = require("express"); const router = express.Router(); const bcrypt = require('bcryptjs'); const User = require('../../models/User'); const jwt = require('jsonwebtoken'); const keys = require('../../config/keys'); const passport = require('passport'); const validateRegisterInput = require('../../validation/register'); const validateLoginInput = require('../../validation/login'); router.post('/register', (req, res) => { const { errors, isValid } = validateRegisterInput(req.body); if (!isValid) { return res.status(400).json(errors); } User.findOne({ email: req.body.email }) .then(user => { if (user) { // errors.name = "User already exists"; return res.status(400).json({ email: "A user has already registered with this address"}) } else { const newUser = new User(req.body); // don't store plaintext password bcrypt.genSalt(10, (err, salt) => { bcrypt.hash(newUser.password, salt, (err, hash) => { if (err) throw err; newUser.password = hash; newUser .save() .then(user => { const payload = { id: user.id, name: user.name }; jwt.sign(payload, keys.secretOrKey, { expiresIn: 86400 * 7 }, (err, token) => { res.json({ success: true, token: "Bearer " + token }); }); }) .catch(err => console.log(err)); }); }); } }); }) router.post('/login', (req, res) => { const { errors, isValid } = validateLoginInput(req.body); if (!isValid) { return res.status(400).json(errors); } const email = req.body.email; const password = req.body.password; User.findOne({email}) .then(user => { if (!user) { errors.name = "This user does not exist"; return res.status(404).json({email: 'This user does not exist'}) } bcrypt.compare(password, user.password) .then(isMatch => { if (isMatch) { const payload = { id: user.id, name: user.name }; jwt.sign(payload, keys.secretOrKey, {expiresIn: 3600 }, (err, token) => { res.json({ success: true, token: 'Bearer ' + token }); }); } else { errors.password = "Incorrect password"; return res.status(400).json({password: 'Incorrect password'}); } }) }) })
Решение проблемы так же хорошо, как и эти сексуальные чувства… иногда, ладно, а может и нет. Прямо из Морган Хилл, Калифорния. Удачи!
Стивен Ласерда