Fastify-passport req.user 为空,反序列化器永远不会被调用,序列化器也不会被调用

Fastify-passport req.user is null, deserializer never gets called nor does the serializer

我一直在努力使用 fastify-passport 库,主要是因为似乎没有人使用它,也没有任何好的例子或与之相关的问题

无论如何,我有一些这样定义的路线:

const adminRoutes = [
  {
    handler: (req,res) => {console.log(req.user) },
    url: "/logout",
    method: "GET"
  }
]

这条路由然后被fastify这样注册了(注意还有更多的路由,不过这只是一个代码片段)

adminRoutes.forEach((route, index) => {
  fastify.route(route)
})

我正在使用护照本地策略进行身份验证,它是这样配置的

fastifyPassport.use('login', new passportLocal(async function (username, password, done) {
  try {
    let data = await dbQuery(`SELECT * FROM \`users\` WHERE username="${username}"`)
    if (data[0].length > 0) {
      data = data[0][0]
      if (username === data.username && bCrypt.compareSync(password, data.hashedPassword)) {
          return done(null, username)
        } else return done(null, false)
      }
  } catch (error) {
    console.log(error)
      done(error);
    }
}))

这似乎有效,在我所有的测试中,该策略完成了它必须做的事情,当通过了正确的用户和密码时,所有检查似乎都通过了并一直到 return done(null, username)

这是我的序列化器和反序列化器

fastifyPassport.registerUserSerializer(async (user, request) => {
  return user
});
fastifyPassport.registerUserDeserializer(async (username, request) => {
  let data = await dbQuery(`SELECT * FROM users WHERE username="${username}"`);
  return data[0][0]
});

我已经检查了调试器和控制台日志,它们似乎从未被调用过

事实上,当我进入 /logout 时,我的控制台抛出一个 null

也没有生成会话 cookie(不确定,有时它似乎生成,其他时候却没有)

完整的代码比较长,不过有必要看看是什么问题

就是这样

这是服务器

require('dotenv').config()
const fastify = require('fastify')({ logger: false })
const fastifyPassport = require('fastify-passport')
const fastifySecureSession = require('fastify-secure-session')
const passportLocal = require('passport-local').Strategy
const BannedEverywhere = ["DROP", "CREATE"]
const bCrypt = require('bcryptjs')
const fs = require('fs')
const path = require('path')
const port = process.env.PORT || 3000
const routes = require('./routes')
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: process.env.DB_PASSWD,
  database: 'users',
  port: 3306
});
console.log("Server Connected!")
function dbQuery(dataExpression) {
  if (BannedEverywhere.some(i => dataExpression.includes(i))) {
    return "invalid"
  }
  return pool.query(dataExpression)
}
fastify.register(require('fastify-cors'), {
  origin: (origin, cb) => {
    cb(null, true);
    return
  }
})
fastify.register(fastifySecureSession, { key: fs.readFileSync(path.join(__dirname, 'secret-key'))})
fastify.register(fastifyPassport.initialize())
fastify.register(fastifyPassport.secureSession())
fastifyPassport.registerUserSerializer(async (user, request) => {
  return user
});
fastifyPassport.registerUserDeserializer(async (username, request) => {
  let data = await dbQuery(`SELECT * FROM users WHERE username="${username}"`);
  return data[0][0]
});
fastifyPassport.use('login', new passportLocal(async function (username, password, done) {
  try {
    let data = await dbQuery(`SELECT * FROM \`users\` WHERE username="${username}"`)
    if (data[0].length > 0) {
      data = data[0][0]
      if (username === data.username && bCrypt.compareSync(password, data.hashedPassword)) {
          console.log("got here")
          return done(null, username)
        } else return done(null, false)
      }
  } catch (error) {
    console.log(error)
      done(error);
    }
}))

const postData = async (req, reply, err, user, info, status) => {
  if (err !== null) { console.warn("ah habido un error: " + err) }
  else if (user) {
    const params = req.body
    const newData = {
      universidad: params.universidad,
      facultad: params.facultad,
      nombreExamen: params.nombreExamen,
      fechaExamen: params.fechaExamen,
      convocatoriaEspecial: params.convocatoriaEspecial,
      convocatoriaExtraordinaria: params.convocatoriaExtraordinaria,
      curso: params.curso
    }
    const response = await dbQuery('INSERT INTO `examenes` VALUES("'
      + newData.universidad + '","' + newData.facultad + '","'
      + newData.nombreExamen + '","' + newData.fechaExamen + '",'
      + newData.convocatoriaEspecial + ',' + newData.convocatoriaExtraordinaria + ','
      + newData.curso + ")")
    return reply.send({ status: 200, newData, response })
  }
}
const deleteData = async (req, reply, err, user, info, status) => {
  if (err !== null) { console.warn("ah habido un error: " + err) }
  else if (user) {
    const { universidad, facultad, nombreExamen, fechaExamen, curso } = req.body
    const response = await dbQuery('DELETE FROM `examenes` WHERE universidad="' + universidad + '" and facultad="' + facultad + '" and nombreExamen="' + nombreExamen + '" and date(fechaExamen)="' + fechaExamen + '" and curso=' + curso)
    return reply.send({ status: 200, response })
  }
}
const logout = async (req, reply, err, user, info, status) => {
  if (err !== null) { console.warn("ah habido un error: " + err) }
  console.log(req)
  console.log("--------------------------------")
  console.log(user)
  console.log("--------------------------------")
  console.log(info)
  console.log("--------------------------------")
  console.log(status)
}

fastify.get(
  "/login",
  (req, reply) => {
    return reply.sendFile('./login/index.html')
  }
)

fastify.post(
  "/login",
  {preValidation: fastifyPassport.authenticate('login',(req, reply)=>{
    reply.send({redirect: "/"})
  })},
  () => {}
)

const adminRoutes = [
  {
    handler: () => {},
    preValidation: fastifyPassport.authenticate("login", deleteData),
    url: '/api/deleteData',
    method: 'POST'
  },
  {
    handler: () => {},
    preValidation: fastifyPassport.authenticate("login", postData),
    url: '/api/postData',
    method: 'POST'
  },
  {
    handler: () => {},
    preValidation: fastifyPassport.authenticate("login", (req, reply) => { return reply.sendFile('./entry/index.html') }),
    url: '/entry',
    method: 'GET'
  },
  {
    handler: (req,res) => {console.log(req.user) },
    url: "/logout",
    method: "GET"
  }
]

const start = async () => {
  try {
    await fastify.listen(port)
  } catch (err) {
    console.error(err)
    process.exit(1)
  }
}

fastify.register(require('fastify-static'), {
  root: __dirname,
  prefix: '/', // optional: default '/'
})
routes.forEach((route, index) => {
  fastify.route(route)
})
adminRoutes.forEach((route, index) => {
  fastify.route(route)
})

start()

在你发表评论之前,我知道 cors 不应该像这样留在生产中,别担心,我知道

另外logout功能只是一个测试,试图解决这个问题

这是调用 login post 请求的代码

        const HOST = location.origin;
        const axiosApp = axios.create({
            baseURL: HOST,
        });
        document
            .querySelector("#submit")
            .addEventListener("click", async function () {
                let response = await axiosApp.post(`${HOST}/login`, {
                    username: document.querySelector("#username").value,
                    password: document.querySelector("#password").value,
                });
                console.log(response);
                if(response.status == 200) {
                    document.location.href = response.data.redirect
                }
            });

无关,bannedEverywhere 只是一个基本的“安全”检查,我确实计划改进它,现在总比没有好,而且,我确实计划用模板更改所有 var + string + var 链字符串

回答我自己的问题:

当您在 preValidation 中添加回调时

{preValidation: fastifyPassport.authenticate('login',(req, reply)=>{
    reply.send({redirect: "/"})
  })}

fastify-passport 不再自行处理序列化和反序列化,随之而来的是......更多问题,将预验证更改为

{preValidation: fastifyPassport.authenticate('login'{successRedirect:"/"})

使您必须在浏览器中处理 302 代码,这至少可以说是有问题的