Multer 认证中间件前后

Multer before and after authentication middleware

我正在使用 express 创建一个 API。

我正在接收多部分形式的数据。我想上传图片,但必须在用户通过身份验证后才能上传。

这是我创建的用于验证用户身份的中间件:

const jwt = require('jsonwebtoken');
const pool = require('../utils/connectionPool');

function authorizeUser(req, res, next){

    try{

        const authHeader = req.headers.authorization;
        const token = authHeader && authHeader.split(' ')[1];
        if(token==null) return res.json({
            status: 000,
            msg: "Token Missing"
        });

        //TODO: Change secret.
        jwt.verify(token, 'mysecret', async (err, user)=>{

            if(err){
                // console.log(err);
                res.json({
                    status: 001,
                    msg: "Invalid Token."
                });
                return;
            }

            if(req.body.id == undefined || req.body.id != user.id){

                res.json({
                    status: 002,
                    msg: "User not authenticated."
                });
                return;

            }

            let login_timestamp = user.login_timestamp;
            
            //Check login token in db.
            let checkToken = await pool.query(`SELECT status FROM user WHERE id=? AND login_timestamp=?`, [user.id, login_timestamp]);

            if(checkToken.length > 0){

                if(checkToken[0].status == 0){
                    res.json({
                        status: 004,
                        msg: "Auth failed. Account Disabled."
                    });
                    return;
                }

                next();
            }else{
                res.json({
                    status: 003,
                    msg: "Timestamp does not match."
                });
                return;
            }
        });
    }catch(e){
        // console.log(e);
        res.json({
            status: 005,
            msg: "User auth failed. Internal Server Error."
        });
        return;
    }
}

所以要访问 req.body,我需要先使用 multer.single("image") 作为中间件。

现在,如果我在使用 authorizeUser 之前使用 multer.single("image"),那么即使在检查用户的身份验证之前,也会先上传图像。如果我在 authorizeUser 之后使用它,那么我将无法访问 authorizeUser 中的 req.body。如果我使用这个中间件顺序:multer.none(), authorizeUser, multer.single("image") 然后它不会上传图像。

如何解决这个问题?如何在authorizeUser中访问req.body时先授权User然后上传图片?

这是我要解析多格式数据的代码:

const express = require('express')
const bodyparser = require('body-parser');
const pool = require('./utils/connectionPool')
const multer = require('multer');

const app = express()
app.use(bodyparser.json());
app.use(express.urlencoded({extended: true}))
const port = 3000

// @beyondhelloworld by Femin Dharamshi

const login = require('./routes/login');
const {authorizeUser} = require('./utils/auth');

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + file.originalname)
  }
})

var upload = multer({ storage: storage })

app.get('/', upload.single('image'), authorizeUser, async (req, res) => {

  //This is just for trial.
  resp = await pool.query("SELECT * FROM user WHERE id=?",[req.body.id]);
  res.json(resp)
})

app.use('/login', login);

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

编辑: TL;DR 我想在文件上传之前访问 req.body。

修改你的代码如下

uploadRouter.post('/path',fileuploadFunction)

const fileuploadFunction = async (req,res) => {

   // Here you should be able to read your body
      await authorizeUser(req.body.id)

   // Upload file
      await uploadFile(req,res)  

}

const uploadFile = util.promisify(multer({ storage: yourStorage, limits, fileFilter }).single('file'))

这就是你使用multer授权上传图片的方式。

没有前端来测试文件上传,您需要使用您想要的 API 来模拟请求。我在这个例子中使用 postman.

首先,在邮递员中设置您的请求。 您必须对要测试的端点使用 POST 请求。

截图如下:

注意在正文选项卡中你必须使用form-data,为key输入一个值(我已经使用image) 并在值旁边的下拉菜单中(左侧),使用 file。现在您可以上传图片了。

其次,你的代码...(注意我已经为这个测试删除了很多噪音和不必要的代码,但无论如何你仍然能够解决问题):

const express = require('express')
const bodyparser = require('body-parser');
const multer = require('multer');
const upload = multer();

const port = 3000

function authorizeUser(req, res, next) {
    
    // we are setting this variable to false initially
    // so that you can run your checks, make DB calls, whatever...
    const isAuthorized = false;

    // if is not authorised
    // the middleware send a not authorised response

    if (!isAuthorized) {
        return res.send("User Not Authorised");
    }

    // if the user is authorised we call next

    next();
    
}

const app = express();

app.use(bodyparser.json());
app.use(express.urlencoded({ extended: true }))

// for simplicity I am using just a post endpoint to test things

app.post('/', upload.single('image'), authorizeUser, (req, res) => {

    // here you save the image in a variable `file` IF
    // only IF the middleware has checked the user in...
   
    const file = req.file;

     // and you can now log / use the file...
    console.log(file);


    // send a response back to the user
    // this won't get executed if the middleware return unauthorised

    res.send("User authorised");
    res.end();

})


app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})

现在,一旦您对代码进行了必要的调整,请点击“发送”通过邮递员发送请求。

由于变量isAuthorised为false(模拟未授权用户的初始值),从postman GUI可以看出,返回给用户的响应是:"User Not授权.

现在检查你的服务器日志;如您所见,没有文件打印到控制台。

接下来,将变量 isAuthorised 更改为 true 并通过邮递员重新发送请求(您可能需要重新启动服务器...)。

查看回复:“用户授权”

再次检查服务器日志,现在您可以看到文件已加载并可用于进一步处理:

  {
    fieldname: 'image',
    originalname: 'myAvatar.png',
    encoding: '7bit',
    mimetype: 'image/png',
    buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 c8 00 00 00 c8 08 06 00 00 00 ad 58 ae 9e 00 00 20 00 49 44 41 54 78 9c ec 9d 77 5c 14 e7 d6 ... 27133 more bytes>,
    size: 27183
   }

这有帮助吗?