Промежуточное программное обеспечение Express.js выполняется для маршрута, определенного выше
Из того, что я прочитал здесь и здесь, порядок, в котором вы размещаете свою функцию промежуточного программного обеспечения, имеет значение, так как вы можете иметь определенные маршруты, которые не проходят через функцию промежуточного программного обеспечения, если она находится перед маршрутом, а маршруты, размещенные после, пройдут через эта функция промежуточного программного обеспечения.
Я вижу смешанные результаты, так как моя среда разработки не соблюдает это, а моя среда разработки - это так. Код точно такой же.
Я пытаюсь сделать так, чтобы мой маршрут входа не был защищен функцией промежуточного программного обеспечения для проверки токена, а остальные мои маршруты были защищены токеном.
Вот мой код:
routes.get('/login', function(req, res) {
// login user, get token
});
routes.use(function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['access-token'];
// decode token
if (token) {
// validate token
}
else if (req.method === 'OPTIONS') {
next();
}
else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
routes.get('/query/:keywords', function(req, res) {
console.log(req.params.keywords);
// execute query
});
app.use('/', routes);
/query
только ли маршрут должен пройти через функцию промежуточного программного обеспечения токена? Прямо сейчас я получаю /login
Маршрут также проходит через функцию промежуточного программного обеспечения токена, что не имеет смысла, так как мне не нужно иметь токен для входа в систему.
Еще лучше, если есть способ определить, какие маршруты я хочу защитить и какие маршруты я не хочу защитить, это лучше, чем полагаться на "порядок" размещения функции промежуточного программного обеспечения.
3 ответа
Во-первых, следуйте этому примеру в ExpressJS:
Более чем одна функция обратного вызова может обрабатывать маршрут (убедитесь, что вы указали следующий объект). Например:
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
Вы заметите, что это определение близко к тому, что вы заявляете routes.use(yourFunction(...))
, Тем не менее, нет никакой реальной причины делать это таким образом, кроме следующих примеров, которые вы видели в документации, что, тем не менее, является хорошим способом начать.
Тем не менее, это ненадежная реализация, экспресс позволит иерархии внутри .get()
.post()
методы, это правильно, но это конкретный случай использования, а не то, что вы ищете.
Что вам нужно, это реализовать свой собственный процесс аутентификации с использованием конфигурации двойного обратного вызова. сделай это:
// You can save this function in a separate file and import it with require() if you want
const tokenCheck = function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['access-token'];
// decode token
if (token) {
// validate token
}
else if (req.method === 'OPTIONS') {
next();
}
else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
routes.get('/login', function(req, res) {
// login user, get token [Unprotected]
});
routes.get('/query/:keywords', tokenCheck, function(req, res) {
console.log(req.params.keywords);
// execute query [Protected with tokenCheck]
});
app.use('/', routes);
Возможно, вам придется поиграться с приведенным выше кодом, но он будет направлять вас в правильном направлении, таким образом, вы можете указать конкретные маршруты для выполнения tokenCheck(req, res, next)
функционируй как хочешь.
Самый простой способ сделать это - использовать промежуточное программное обеспечение маршрутизатора для выделения маршрутов, требующих аутентификации, и маршрутов, которые не требуют. Поскольку все маршрутизаторы являются промежуточным ПО, мы можем реализовать их так же, как и любое другое промежуточное ПО. Гарантируя, что мы размещаем Маршрутизаторы и Маршруты в том порядке, в котором мы хотим, чтобы наши Маршруты оценивались.
В приведенном ниже примере сервер Express имеет 2 маршрутизатора, LoginRouter и ApiRouter.
LoginRouter
- генерирует токен при получении запросаPOST /login
и возвращает это запрашивающей стороне для последующего использования в/api
маршруты.ApiRouter
- Оборачивает все остальные маршрутизаторы, централизует промежуточное ПО, которое необходимо применять глобально ко всем маршрутам в /api. Доступно только для аутентифицированных запросов.
Маршрутизатор API доступен только в том случае, если токен включен в заголовок и этот токен получен из LoginRouter. LoginRouter не требует аутентификации.
С этой настройкой вы будете добавлять маршрутизаторы после промежуточного программного обеспечения авторизации в API-маршрутизатор через .use()
на ApiRouter.
Приведенная ниже схема создания маршрутизаторов из других маршрутизаторов очень мощная, масштабируемая и простая в обслуживании.
server.js
const express = require('express')
const bodyParser = require('bodyParser')
const ApiRouter = require('./routes/api')
const LoginRouter = require('./routes/login')
const port = process.env.PORT || 1337
const server = express()
server.use(bodyParser.json())
server.use('/login', LoginRouter)
server.use('/api', ApiRouter)
server.listen(port, () => console.log(`Listening on ${port}`))
LoginRouter - /routes/login.js
const router = require('express').Router()
router.post('/', (req, res) => {
// Validate Credentials
// some validation code...
// Then create the token for use later in our API
let token = '...'
// Response 200 OK with the token in the message body
return res.status(200).send({token})
})
module.exports = router
ApiRouter - /routes/api/index.js
const router = require('express').Router()
const UsersRouter = require('./routes/api/users')
router.use((req, res, next) => {
let authorizationHeader = req.headers['authorization'] || req.headers['Authorization'] // handle lowercase
let [, token] = authorizationHeader.split(' ')
if (!token) {
return res.sendStatus(403) // Forbidden, you're not logged in
} else {
// validate the token
if (!tokenIsValid) {
return res.sendStatus(403) // Forbidden, invalid token
}
// Everything is good, continue to the next middleware
return next()
}
})
router.use('/users', UsersRouter)
module.exports = router
UsersRouter - / routs/api/users
const router = require('express').Router()
router.get('/', (req, res) => {
// We only get here if the user is logged in
return res.status(200).json({users: []})
})
module.exports = router
Применение промежуточного программного обеспечения токена не должно происходить с маршрутом входа в систему из-за порядка маршрутов и того факта, что маршрут входа в систему никогда не вызывает следующий объект. Без дополнительной информации мы действительно не сможем определить, что происходит дальше, однако вы можете попытаться проверить это в своей среде разработки с перерывом в отладчике и посмотреть на требование, которое попадает в это промежуточное ПО.
Тем не менее, мы можем предоставить вам некоторую информацию о том, как попытаться изолировать ваше промежуточное ПО.use и как применяется приложение порядка промежуточного ПО, чтобы вы могли попробовать отделить его от маршрута входа в систему, как показано в нижней части вашего вопроса.
При применении промежуточного программного обеспечения только к определенным маршрутам следует помнить, что order и.use относятся к промежуточному программному обеспечению, которое должно ответить на запрос, прежде чем сообщать Express, чтобы продолжить поиск другого промежуточного программного обеспечения, которое следует за ними в маршрутизаторе, который также будет обрабатывать запрос. Если вы хотите использовать его только для нескольких маршрутов, вы можете добавить его только к нескольким маршрутам, указав следующее:
router.get('/route', [ middleware1, middleware2, ..., middlewareX])
или же
router.get('/route', middleware1, middleware2, ..., middlewareX)
оба шаблона будут работать. Однако я нахожу шаблон массива немного более приемлемым, так как я могу определить множество промежуточных продуктов, которые я хочу применить, и затем объединить новое промежуточное программное обеспечение для конкретной логики, и мне нужно только изменить то место, где я объявляю эту конкатенацию, чтобы добавить больше функциональности. Однако такое промежуточное программное обеспечение редко понадобится, и вы сможете использовать и то и другое.
Вы также можете разделить это промежуточное ПО на подмножество маршрутов, используя маршрутизатор и применяя его в качестве первого промежуточного программного обеспечения в цепочке маршрутов до маршрутизатора.
app.use('/user', authentication, userRouter)
или вы можете поместить его в маршрутизатор в качестве первого промежуточного программного обеспечения с.use, чтобы он обрабатывал все запросы.
Запомните общие советы по использованию промежуточного программного обеспечения:
- порядок имеет значение для приложения промежуточного программного обеспечения
- дополнительное промежуточное программное обеспечение, которое должно применяться на основе маршрута, должно применяться с другим промежуточным программным обеспечением только для этого маршрута
- промежуточное ПО для обработки ошибок всегда должно быть последним и иметь четыре аргумента (err, req, res, next)
- использовать маршрутизаторы для разделения промежуточного программного обеспечения.use на конкретные маршруты и наборы маршрутов.
Вы можете найти более подробную информацию об этом в документации к промежуточному программному обеспечению для expressjs.