如何在带有supertest,passport和JEST的cookie中使用jwt测试身份验证

迈克尔·吉

大家好,我目前正在尝试执行类似于此处发布的操作:如何使用Passport验证超级测试请求?

正如我想测试需要身份验证但还需要传入jwt的其他端点。现在,我在POSTMAN和浏览器上对其进行了测试,看起来它工作正常,但我的测试用例一直在中断。我有一个这样的登录POST路由:

AccountService.js

// Login POST route
  router.post('/account_service/login', (req, res, next) => {
    passport.authenticate('local-login', (err, user, info) => {
      try {
        if (err) {
          const error = new Error('An Error occurred: Cannot find user');
          return next(error);
        } else if (!user) {
          return res.redirect('/account_service/login');
        }
        req.login(user, { session: false }, (error) => {
          if (error) {
            return next(error);
          }
          const email = req.body.email;
          const role = req.user[0].role;
          const id = req.user[0].id;

          const user = {
            email: email,
            role: role,
            id: id
          };
          const accessToken = jwt.sign(user, config.ACCESS_TOKEN_SECRET, {
            expiresIn: 28800 // expires in 8 hours
          });
          const cookie = req.cookies.cookieName;
          if (cookie === undefined) {
            // set a new cookie
            console.log('setting new cookie');
            res.cookie('jwt', accessToken, { maxAge: 900000, httpOnly: true });
            res.send({ token: accessToken });
          } else {
            // cookie was already present
            console.log('cookie exists', cookie);
          }
          res.redirect('/account_service/profile');
        });
      } catch (error) {
        return next(error);
      }
    })(req, res, next);
  });

在对用户进行身份验证之后,我为该用户分配一个JSON Web令牌并将其放置在Cookie中,以便将其存储在授权请求的标头中。这是一个例子:

AccountService.js

// Get all users
  router.get('/account_service/all_users', passport.authenticate('jwt', { session: false }), (req, res, next) => {
    const sql = 'select * from user';
    const params = [];
    db.all(sql, params, (err, rows) => {
      if (err) {
        res.status(500).json({ error: err.message });
        return;
      }
      res.json({
        message: 'success',
        data: rows
      });
    });
  });

我使用passport.authenticate来确保jwt有效。仅当我使用管理员用户帐户登录后,此GET请求才起作用。

在我的护照文件中,我进行了如下设置:

护照

const LocalStrategy = require('passport-local').Strategy;
const db = require('../database.js');
const bcrypt = require('bcrypt');
const config = require('../config/config.js');
const JwtStrategy = require('passport-jwt').Strategy;

const cookieExtractor = function (req) {
  var token = null;
  if (req && req.cookies) token = req.cookies.jwt;
  return token;
};

module.exports = function (passport) {
  passport.serializeUser(function (user, done) {
    done(null, user);
  });
  passport.deserializeUser(function (user, done) {
    done(null, user);
  });
  passport.use('local-login', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true
  }, (req, email, password, done) => {
    try {
      const sql = `select * from user WHERE email = "${email}"`;
      const params = [];
      db.all(sql, params, (err, row) => {
        if (err) {
          return done(err);
        }
        if (!row.length || !bcrypt.compareSync(password, row[0].password)) {
          return done(null, false, req.flash('loginMessage', 'Inavalid username/password combination. Please try again.'));
        }
        return done(null, row);
      });
    } catch (error) {
      return done(error);
    }
  }));

  const opts = {};
  opts.jwtFromRequest = cookieExtractor; // check token in cookie
  opts.secretOrKey = config.ACCESS_TOKEN_SECRET;
  // eslint-disable-next-line camelcase
  passport.use(new JwtStrategy(opts, function (jwtPayload, done) {
    try {
      const sql = `select * from user WHERE email = "${jwtPayload.email}"`;
      const params = [];
      db.all(sql, params, (err, row) => {
        if (err) {
          return done(err);
        }
        if (!row.length || !bcrypt.compareSync('admin', jwtPayload.role)) {
          return done(null, false, { message: '403 Forbidden' });
        }
        return done(null, row);
      });
    } catch (error) {
      return done(error);
    }
  }));
};

这是我的测试用例中断时感到困惑的地方。我试图在测试用例之前登录,以允许其他测试用例运行,但最终出现401错误。这是我的测试用例:

accountservice.test.js

const app = require('../../app');
const supertest = require('supertest');
const http = require('http');

describe('Account Service', () => {
  let server;
  let request;

  beforeAll((done) => {
    server = http.createServer(app);
    server.listen(done);
    request = supertest.agent(server);
    request.post('/account_service/login')
      .send({ email: '[email protected]', password: 'admin' })
      .end(function (err, res) {
        if (err) {
          return done(err);
        }
        console.log(res);
        done();
      });
  });

  afterAll((done) => {
    server.close(done);
  });

  it('Test request all users endpoint | GET request', async done => {
    const response = await request.get('/account_service/all_users');
    expect(response.status).toBe(200);
    expect(response.body.message).toBe('success');
    expect(response.body.data.length).toBe(3);
    done();
  });
});

但是我的测试用例失败,因为当我期望成功代码为200时,我收到401错误。

我尝试过考虑在登录调用后从cookie中提取jwt的方法,以便可以为/ account_service / all_users GET请求代码设置标头,但无法使用Supertest找到方法。我看到了这篇文章:使用Mocha + supertest +护照使用JWT测试经过身份验证的路由失败,但是看到它从主体获取令牌。

迈克尔·吉

在弄乱了我的代码之后,我最终遇到了内存存储问题,并运行了异步db.run函数,这些函数在每次运行服务器时都会调用。因此,我使用一个文件来存储我的数据,然后再次运行我的测试,结果一切正常!

这是错误的代码:

const sqlite3 = require('sqlite3').verbose();
const md5 = require('md5');

const DBSOURCE = ':memory:';

const db = new sqlite3.Database(DBSOURCE, (err) => {
  if (err) {
    // Cannot open database
    console.error(err.message);
    throw err;
  } else {
    db.run(`CREATE TABLE user (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name text, 
        email text UNIQUE, 
        password text, 
        status text,
        comments text, 
        photos text,
        CONSTRAINT email_unique UNIQUE (email)
        )`,
    (err) => {
      if (err) {
        // Table already created
        console.log('Table already created');
      } else {
        // Table just created, creating some rows
        const insert = 'INSERT INTO user (name, email, password, status, comments, photos) VALUES (?,?,?,?,?,?)';
        db.run(insert, ['user_delete', '[email protected]', md5('admin123456'), 'pending_deleted', 'comment1,comment2', 'https://giphy.com/gifs/9jumpin-wow-nice-well-done-xT77XWum9yH7zNkFW0']);
        db.run(insert, ['user_no_delete', '[email protected]', md5('user123456'), 'active', 'comment1', 'https://giphy.com/gifs/cartoon-we-bare-bears-wbb-NeijdlusjcduU']);
        db.run(insert, ['mikey', '[email protected]', md5('mikey123'), 'pending_deleted', 'comment1', 'https://giphy.com/gifs/wwe-shocked-vince-mcmahon-gdKAVlnm3bmKI']);
      }
    });
  }
});

module.exports = db;

我只是将这些数据存储在文件中,而是使用以下代码:

const sqlite3 = require('sqlite3').verbose();
const DBSOURCE = 'mockdb.sqlite';

// Data inserted inside file
/*
db.run(insert, ['user_delete', '[email protected]', bcrypt.hashSync('admin123456', saltRounds), 'pending_deleted', 'comment1,comment2', 'https://giphy.com/gifs/9jumpin-wow-nice-well-done-xT77XWum9yH7zNkFW0', bcrypt.hashSync('user', saltRounds)]);
db.run(insert, ['user_no_delete', '[email protected]', bcrypt.hashSync('user123456', saltRounds), 'active', 'comment1', 'https://giphy.com/gifs/cartoon-we-bare-bears-wbb-NeijdlusjcduU', bcrypt.hashSync('user', saltRounds)]);
db.run(insert, ['mikey', '[email protected]', bcrypt.hashSync('mikey123', saltRounds), 'pending_deleted', 'comment1', 'https://giphy.com/gifs/wwe-shocked-vince-mcmahon-gdKAVlnm3bmKI', bcrypt.hashSync('user', saltRounds)]);
db.run(insert, ['admin', '[email protected]', bcrypt.hashSync('admin', saltRounds), 'active', 'admincomments', 'adminphoto', bcrypt.hashSync('admin', saltRounds)]);
  console.log('last hit in database');
});
*/

const db = new sqlite3.Database(DBSOURCE, (err) => {
  if (err) {
    // Cannot open database
    console.error(err.message);
    throw err;
  }
  console.log('Connection successful!');
});

module.exports = db;

我最终也使用了supertest.agent。

const app = require('../../app');
const supertest = require('supertest');
const http = require('http');
const db = require('../../database/database.js');

describe('Account Service', () => {
  let server;
  let request;
  // Find cookie management option.
  beforeAll(async (done) => {
    server = http.createServer(app);
    server.listen(done);
    request = supertest.agent(server);
    done();
  });

最终工作成功解决了我的问题!

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

无法再次使用Jest,Supertest,Passport和Koa2在测试中发送经过身份验证的请求

无法在使用 Jest、Supertest、Passport、Koa2 的测试中发送经过身份验证的请求

如何在 OWIN 应用程序中使用 cookie 身份验证和 WsFederation 身份验证

如何在基于类的视图中使用 django REST JWT 授权和身份验证

如何使用Supertest和Agent在Mocha测试中提出经过身份验证的请求?

如何在我的HTTP请求中使用带有身份验证的代理?

如何在带有Servicestack的.NET Core中使用Windows身份验证登录

如何使用JWT和Passport正确使用对nodeJs API的身份验证?

如何使用Laravel Passport通过API测试身份验证?

如何在asp.net core 2.2中实现Cookie基础身份验证和jwt?

如何在Laravel和Vue.js中使用jwt-auth检查用户是否已通过身份验证

如何使用 Postman 测试 jwt 身份验证

如何使用REST Framework JWT测试身份验证?

如何在graphene-django GraphQLTestCase中使用django-grahql-jwt进行身份验证?

如何在Python中使用JWT实现基于角色的身份验证

如何在 JWT 中使用 CakePHP3“身份验证”插件

使用Node.js和Passport进行身份验证后,如何将用户重定向至带有其ID的主页?

如何在Django中使用Pytest测试经过身份验证的POST请求

如何在 Laravel 5 中使用 Codeception 在单元测试中模拟身份验证用户?

如何同时使用Cookie和BASIC身份验证?

如何在angularjs Web API SPA中使用现有的基于Web表单的身份验证和授权?

如何在没有邮箱的情况下使用带有Windows身份验证和身份的EWS发送和保存电子邮件?

如何在 ADFS 中使用自定义身份验证替换主要身份验证

如何使用带有URL和基本身份验证凭据的scrapy shell?

如何使用带有反应本机和反应导航的 Firebase 电子邮件身份验证

如何在Phoenix框架中使用Ueberauth和Guardian对用户进行身份验证

如何在基本身份验证中使用RestTemplate

如何在公司环境中使用LDAP身份验证

如何在NGRX中使用身份验证防护