Обновлять!!!
В конце концов я решил заебаться и просто попытался защитить свой API в качестве первого шага к аутентификации. Вот мои коммиты на сегодня (пока).
Прежде всего, я взял за основу свой код этот потрясающий блог Джонатана М.Х.. Я добавил еще несколько зависимостей, таких как Passport, Passport-JWT и JWTWebtoken.
Я использовал JWTStrategy в качестве своей стратегии и просто сделал быстрый вход в систему для проверки электронной почты и пароля. Вот репо для всех, кому интересно.
Итак, я объявил метод для создания JWT в моей пользовательской модели. Не знаю, правильно ли я это делаю, но я старался сделать свои контроллеры тощими, а модели — толстыми.
На этом пути я столкнулся с множеством проблем, таких как отсутствие переменной jwt. Итак, я рассмотрел, как работает module.exports
, и, похоже, у меня очень поверхностное понимание предмета. Исходя из своего понимания, я сделал файл, в котором размещались все мои модули паспорта и JWT.
Не знаю, правильно ли я это делаю, но я все равно пытался. Попутно я также обнаружил распространенную ошибку Node.js, которая называется круговая зависимость. Я чуть не ударился головой о стол, потому что мой экспортируемый модуль не определен. Я понял, что перезаписываю свой собственный модуль на своей модели. Видимо, я вызываю его дважды, поэтому я сделал небольшой хак и назвал свою модель предпоследним (перед моим окончательным экспортом).
var jwt = require('jsonwebtoken'); var passport = require("passport"); var passportJWT = require("passport-jwt"); var ExtractJwt = passportJWT.ExtractJwt; var JwtStrategy = passportJWT.Strategy; exports.jwt = jwt; exports.passportJWT = passportJWT; exports.ExtractJwt = ExtractJwt; exports.JwtStrategy = JwtStrategy; exports.jwtOptions = { jwtFromRequest : ExtractJwt.fromAuthHeaderWithScheme('bearer'), secretOrKey : 'tasmanianDevil' //FIXME: change into this to env vars }; var Users = require('../models/users'); // Only call this after everything else is done so YOU don't overwrite exports!! exports.strategy = new JwtStrategy(this.jwtOptions, function(jwt_payload, next) { console.log('payload received', jwt_payload); Users.findById(jwt_payload.id, function(err, doc) { if (err) { res.send(err); } if (doc) { next(null, doc); } else { next(null, false); } }); }); passport.use(this.strategy); exports.passport = passport;
Итак, я также переработал свой server.js, чтобы он мог вместить паспорт. Как обычно, я не уверен, что делаю это правильно,
const config = require('./api/config'); const passport = config.passport; app.use(passport.initialize()); // some code... usersRoutes(app, passport);
Теперь, когда у меня есть паспорт для аутентификации запросов, я реализовал его как промежуточное ПО в своих маршрутах.
// This route has to go first app.route('/api/users/login') .post(users.login); app.route('/secret') .get(passport.authenticate('jwt', { session: false }), function(req, res){ res.json("Success you can see me"); }); app.route('/api/users/:id') .get(users.single) .post(users.update) .delete(users.delete); app.route('/api/profile') .get(passport.authenticate('jwt', { session: false }), profile.get) .post(passport.authenticate('jwt', { session: false }), profile.update);
Я не знаю, есть ли способ сделать это СУХИМ, но пока этого достаточно. Лучше, чем ничего, верно?
В любом случае, я также изменил схему извлечения авторизации заголовков с JWT на Bearer. В основном потому, что я вижу, что OAuth использует Bearer в качестве префикса. Так что я только готовлюсь к этому. Конечно, это опять же, очередная догадка. Может ли кто-нибудь просветить меня?
jwtFromRequest : ExtractJwt.fromAuthHeaderWithScheme('bearer'),
Пройдя все проверки в middleware, я обнаружил, что в результате передается объект req.user
. И так, я сделал новый контроллер явно для пользователя и вся информация будет извлекаться с помощью полезной нагрузки id в JWT. Еще раз, я не знаю, распространено ли это в мире Node.js, но я все равно это сделал. Чтобы проиллюстрировать, проверьте этот маршрут.
'use strict'; const mongoose = require('mongoose'); const Users = mongoose.model('Users'); exports.get = function(req, res) { res.json(req.user); // Format the fields }; exports.update = function(req, res) { var params = req.body; params.password = Users.hashPassword(params.password); Users.findOneAndUpdate({ _id: req.user.id }, { $set: params }, { new: true, runValidators: true, context: 'query' }, function(err, doc) { if (err) { res.send(err); } res.json(doc); }); };
Без передачи какого-либо идентификатора в параметрах или в теле запроса идентификатор уже предопределен на основе проверок промежуточного программного обеспечения.
Что дальше?
После долгих исследований JWT и аутентификации я обнаружил, что существуют стандарты, особенно в реализации JWT. Срок действия, правильная полезная нагрузка json, содержимое заголовков, токены обновления и многое другое. Ух! Так устрашающе. Но я, наверное, все равно их сделаю.
Сейчас я сосредоточусь на стандартах JWT, так что это мой следующий шаг.
Если вы читаете это, спасибо, что дочитали до конца! До встречи в моих следующих постах! 👋