【问题标题】:Passport authentication in Chai testsChai 测试中的护照认证
【发布时间】:2018-04-09 08:55:06
【问题描述】:

这是我第一个使用护照的项目,总的来说我是 Node 新手。在使用 Chai 运行集成测试时,我无法将端点识别为授权。端点是 通过使用护照和 jsonwebtoken 库的令牌身份验证进行保护。以下是导入到测试中的其他文件;

const chai = require('chai');
const chaiHttp = require('chai-http');
const mongoose = require('mongoose');
const should = chai.should();
const { Session } = require('../models/practiceSession' );
const {User} = require('../models/user');
const { app, runServer, closeServer } = require('../app');
const { TEST_DATABASE_URL } = require('../config/mainConfig');
const {secret} = require('../config/mainConfig');
const jwt = require('jsonwebtoken');
chai.use( chaiHttp );

这里是端点的测试;

//test the session endpoints
       it( 'should return a session with proper request', function(){
          const user = new User({
              name: 'random2',
              email: 'random2@random.com',
              password: 'Password2'
            });


          user.save( (err) => {
            if (err){
              console.log( err.message);
              }
          });

          const token = jwt.sign({
            id: user._id,
            userName: user.name,
            level: 0
            }, secret, {
            expiresIn: 60 * 60
            });

          console.log( "user id: ", user._id);
          console.log( 'token is: ', token );

          const practiceRequest = {
            operation: "+",
            number: "10",  ///this will possible need to be sent as a number
            min: "1",
            max: "200"
          };

          return chai.request(app)
            .post('/api/session')
            .set('Authorization', 'Bearer ' + token)
            .send( practiceRequest )
            .then( (res) => {
              res.should.have.status(201);
            })
          });

    });

两个console.log 语句确认正在创建用户并具有_id 属性,并且正在创建一个有效的令牌 已创建(已在 jwt.io 上确认)。

这是端点的代码;

router.route("/session")
    .post(passport.authenticate('jwt', { session: false }), jsonParser, ( req, res ) => {
        console.log( req );
        let practiceSession = [];  
        for ( let i = 0; i < req.body.number; i++ ){
            let firstTerm = generateTerm( req.body.min, req.body.max );
            let secondTerm = generateTerm( req.body.min, req.body.max );
            const problem = {  
                operator: req.body.operation,
                firstTerm,
                secondTerm,
                problem: `${ firstTerm } ${ req.body.operation } ${ secondTerm }`,
                correctResponse: generateCorrectResponse( firstTerm, secondTerm, req.body.operation )
            }; 
            practiceSession.push( problem );
        }

    // save session into db sessions collection for use in the training-logic.js
        Session
        .create( {
            userId: req.user._id, 
            problems: practiceSession  
        } )
        .then(
            session => res.status( 201 ).json( session) )
        .catch( err => {
            console.error( err );
            res.status( 500 ).json( { message: 'Internal Server Error' } );
        });
    } );

此端点的测试失败,返回 401 响应和简单的Error: Unauthorized 这不是很多信息 而且我不知道在哪里继续排除故障。我的理解是,这意味着最初的passport.authenticate 即使在 jwt.io 站点上已确认它是有效的,端点处的令牌也不会识别为有效。有没有 生成令牌时我应该包括的其他信息?如果有怎么办?

我看过其他几个使用护照的例子; one, two, three 但我做到了 看不到如何将这些见解应用到我的实现中。

对此的任何帮助将不胜感激。感谢您的时间。

更新:

基于有效令牌正在到达端点但仍未被接受的事实,我尝试使用对用户身份验证端点的初始调用构建一个承诺链,然后使用从那里派生的令牌来测试会话生成端点。这就是努力;

     it( 'should return a session with proper request', function(){

       let token; 
       return chai.request(app)
          .post('/api/user/authenticate')
          .send( {
           email: 'random@random.com',
           password: 'password2'
           } )
          .then( (res) => {
            res.should.have.status(200);
            res.should.be.json;
            console.log( res.body );
            token = res.body.token; 
            return token; 
          })
          .catch( (err) => {
            console.log( 'failed at user authentication' );
          })
          .then( ( err, data ) => {
            console.log( 'token value is ', token );
            chai.request( app )
            .post( '/api/session' )
            .set( 'Authorization', `${ token }` )
            .send( {
                operation: "+",
                number: "10",  
                min: "1",
                max: "200"
             })
            .then( res => { 
              console.log( 'second response is ', res );
              res.should.have.status(201);
             } )
            .catch( err => {
              console.log( 'second promise ', err.message );
            })
          })
        });

它仍然被拒绝为Unauthorized。从测试发送到会话端点的请求中缺少某些内容。会话端点中的console.log( req ) 确认它正在接收一个添加了大量信息的对象,与测试中从承诺链发送的信息相比。我不得不在外部范围内使用 token 变量来传递 chai.request(app) 命令之间的值。这与工作应用程序中存在的数据流不同。我不确定如何测试它;我的理解是,到目前为止我所尝试的并没有为端点提供足够的数据来验证请求。

任何帮助将不胜感激。感谢您的时间。

【问题讨论】:

  • Debug 验证调用。
  • James,感谢您的参考,我从未在 Node.js 的服务器端使用过 Chrome 调试器。在应用程序的正常运行中,我在 sessionRouter 端点(上图)中设置了一个断点并检查了请求对象。在标题中有一个authorization: "Bearer eyJhbGciOiJIUzI1NiIsIn..." 的属性我的理解是这是在测试中发送的。这个工具提供了额外的信息,但我认为它证实了我一直在做的事情。我仍然不确定为什么测试因“未经授权”而失败。再次感谢您的宝贵时间。
  • 听起来令牌标头正在上升(这很好)。将您的问题缩小到您的 JWT 无效:)

标签: node.js authentication integration-testing chai passport.js


【解决方案1】:

解决方案

为了跟进,一位朋友帮助解决了这个问题,并给了我一个解决方案,当 构建令牌。最终的工作模型有一个beforeEach() 函数,它将一个虚拟用户添加到测试数据库,然后 将此用户分配给外部范围内的testUser 变量,因此可以在以后的测试中访问它。在实际测试中 端点这个testUser 变量被映射到一个完整的用户模式,并用于构建令牌和测试端点。它运行良好,因为端点具有所需的所有属性。这是代码;

describe( 'End-point for practice session resources', function() {

    let testUser;
    let modelSession; 

    before( function() {
      return runServer( TEST_DATABASE_URL );
    });

    beforeEach( function(done){
      addUser()
      .then( user => {
        testUser = user;
        done(); 
      });
    });

和测试;

 it( 'should generate a session with the proper request (POST)', function(){

          const token = jwt.sign({
            id: testUser._id
          }, secret, { expiresIn: 60 * 60 }); 

          return chai.request( app )
              .post( '/api/session' )
              .set( 'Authorization', `Bearer ${ token }` )
              .send( {
                  operation: "+",
                  number: "10",  
                  min: "1",
                  max: "200"
              })
              .then( res => { 
                res.should.have.status(201);
              } )
            })
          });

希望这可以帮助其他人。

【讨论】:

  • 想澄清一下,通过回顾您的代码实际上很明显,您的问题是您在测试中遇到了竞争条件。您创建您的用户,然后继续发送请求之前您可以确定用户已被保存。我写了一个库,我认为它确实有助于简化您的测试,请查看fluentify,它是专门为解决此类问题而设计的。如果您对此有任何疑问,请告诉我:)
  • 太棒了!谢谢詹姆斯!
  • 不用担心,在我以前的工作中,我们发现自己有很多需要大量设置的集成测试,尽管 Mocha 很棒,但很容易陷入回调地狱或被以下场景绊倒您成功了,它现在已成为自动化测试过程中不可或缺的一部分,并且用于每天运行数千个测试。文档中有一些简单的示例,但是如果您对此感到困惑,我很乐意以要点为指导“流利”您问题中的代码。
猜你喜欢
  • 2017-08-25
  • 2022-11-28
  • 1970-01-01
  • 1970-01-01
  • 2022-08-05
  • 2021-07-01
  • 1970-01-01
  • 2015-09-23
  • 2019-03-01
相关资源
最近更新 更多