Промежуточное программное обеспечение 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, чтобы он обрабатывал все запросы.

Запомните общие советы по использованию промежуточного программного обеспечения:

Вы можете найти более подробную информацию об этом в документации к промежуточному программному обеспечению для expressjs.

Другие вопросы по тегам