web-dev-qa-db-ja.com

Passportでスーパーテストリクエストを認証する方法は?

認証(ローカル戦略)およびMochaとSupertestでのテストにPassport.jsを使用しています。

Supertestでセッションを作成して認証済みのリクエストを行うにはどうすればよいですか?

58
Gal Ben-Haim

そのために superagent を使用する必要があります。それは下位レベルのモジュールであり、supertestによって使用されます。セクションを見てください エージェントの永続化

var request = require('superagent');
var user1 = request.agent();
user1
  .post('http://localhost:4000/signin')
  .send({ user: '[email protected]', password: 'password' })
  .end(function(err, res) {
    // user1 will manage its own cookies
    // res.redirects contains an Array of redirects
  });

これで、user1認証済みリクエストを作成します。

44
zemirco

ZeMircoが指摘しているように、基礎となるsuperagentモジュールはセッションをサポートし、自動的にCookieを維持します。ただし、文書化されていない機能を介して、supertestからsuperagent.agent()機能を使用することは可能です。

require('supertest').agent('url')の代わりにrequire('supertest')('url')を使用するだけです:

var request = require('supertest');
var server = request.agent('http://localhost:3000');

describe('GET /api/getDir', function(){
    it('login', loginUser());
    it('uri that requires user to be logged in', function(done){
    server
        .get('/api/getDir')                       
        .expect(200)
        .end(function(err, res){
            if (err) return done(err);
            console.log(res.body);
            done()
        });
    });
});


function loginUser() {
    return function(done) {
        server
            .post('/login')
            .send({ username: 'admin', password: 'admin' })
            .expect(302)
            .expect('Location', '/')
            .end(onResponse);

        function onResponse(err, res) {
           if (err) return done(err);
           return done();
        }
    };
};
53
Andy

これを試して、

  var request=require('supertest');
  var cookie;
  request(app)
  .post('/login')
  .send({ email: "[email protected]", password:'password' })
  .end(function(err,res){
    res.should.have.status(200);
    cookie = res.headers['set-cookie'];
    done();        
  });

  //
  // and use the cookie on the next request
  request(app)
  .get('/v1/your/path')
  .set('cookie', cookie)
  .end(function(err,res){  
    res.should.have.status(200);
    done();        
  });
26
grub

Andyの答えの補遺として、Supertestがサーバーを自動的に起動するようにするには、次のようにします。

var request = require('supertest');

/**
 * `../server` should point to your main server bootstrap file,
 * which has your express app exported. For example:
 * 
 * var app = express();
 * module.exports = app;
 */
var server = require('../server');

// Using request.agent() is the key
var agent = request.agent(server);

describe('Sessions', function() {

  it('Should create a session', function(done) {
    agent.post('/api/session')
    .send({ username: 'user', password: 'pass' })
    .end(function(err, res) {
      expect(req.status).to.equal(201);
      done();
    });
  });

  it('Should return the current session', function(done) {
    agent.get('/api/session').end(function(err, res) {
      expect(req.status).to.equal(200);
      done();
    });
  });
});
10
Kevin C.

申し訳ありませんが、提案された解決策はどちらも機能しません。

supertest.agent()では、appインスタンスを使用できません。事前にサーバーを実行し、http://127.0.0.1:portさらに、スーパーテストの期待(アサーション)を使用できません。supertest-as-promised libなど...

cookiesケースはまったく機能しません。

だから、私の解決策は:

Passport.jsを使用している場合、「ベアラートークン」メカニズムを利用し、仕様で次の例を使用できます。

var request = require('supertest');
var should = require('should');

var app = require('../server/app.js'); // your server.js file

describe('Some auth-required API', function () {
  var token;

  before(function (done) {
    request(app)
      .post('/auth/local')
      .send({
        email: '[email protected]',
        password: 'the secret'
      })
      .end(function (err, res) {
        if (err) {
          return done(err);
        }

        res.body.should.to.have.property('token');
        token = res.body.token;

        done();
      });
  });

  it('should respond with status code 200 and so on...', function (done) {
    request(app)
      .get('/api/v2/blah-blah')
      .set('authorization', 'Bearer ' + token) // 1) using the authorization header
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        }

        // some `res.body` assertions...

        done();
      });
  });

  it('should respond with status code 200 and so on...', function (done) {
    request(app)
      .get('/api/v2/blah-blah')
      .query({access_token: token}) // 2) using the query string
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        }

        // some `res.body` assertions...

        done();
      });
  });
});

ユーザーを認証するためのヘルパー機能が必要な場合があります。

test/auth-helper.js

'use strict';

var request = require('supertest');
var app = require('app.js');

/**
 * Authenticate a test user.
 *
 * @param {User} user
 * @param {function(err:Error, token:String)} callback
 */
exports.authenticate = function (user, callback) {
  request(app)
    .post('/auth/local')
    .send({
      email: user.email,
      password: user.password
    })
    .end(function (err, res) {
      if (err) {
        return callback(err);
      }

      callback(null, res.body.token);
    });
};

充実した一日を!

6
Dan K.K.

CookieSessionミドルウェアを使用していると仮定します。

Grubが述べたように、あなたの目標はcookie値を取得してリクエストに渡すことです。ただし、何らかの理由で(少なくとも私のテストでは)、スーパーテストは同じテストで2つのリクエストを実行しません。そのため、正しいCookie値を取得する方法をリバースエンジニアリングする必要があります。まず、Cookieを作成するためのモジュールが必要になります。

var Cookie          = require("express/node_modules/connect/lib/middleware/session/cookie")
  , cookieSignature = require("express/node_modules/cookie-signature")

はい、それはいです。これらをテストファイルの先頭に配置します。

次に、Cookie値を作成する必要があります。認証されたユーザーを必要とするテストのために、これをbeforeEachに入れました。

var cookie = new Cookie()
  , session = {
      passport: {
        user: Test.user.id
      }
    }

var val = "j:" + JSON.stringify(session)
val = 's:' + cookieSignature.sign(val, App.config.cookieSecret)
Test.cookie = cookie.serialize("session",val)

Test.user.idは、以前にbeforeEachチェーンの「ログイン」しようとしているユーザーを定義した部分で定義されていました。 sessionの構造は、Passportが(少なくとも現在)セッションに現在のユーザー情報を挿入する方法です。

var valおよび"j:"を含む"s:"行は、Cookieベースのセッションを使用している場合にPassportがフォールバックするConnect CookieSessionミドルウェアから取り出されます。最後に、Cookieをシリアル化します。そこに"session"を配置しました。これが私のCookieセッションミドルウェアの設定方法だからです。また、App.config.cookieSecretは他の場所で定義されており、Express/Connect CookieSessionミドルウェアに渡す秘密でなければなりません。後でアクセスできるように、Test.cookieに格納します。

さて、実際のテストでは、そのCookieを使用する必要があります。たとえば、次のテストがあります。

it("should logout a user", function(done) {
  r = request(App.app)
    .del(App.Test.versionedPath("/logout"))
    .set("cookie", Test.cookie)
    // ... other sets and expectations and your .end
}

"cookie"Test.cookieを使用したsetの呼び出しに注意してください。これにより、リクエストで作成したCookieが使用されます。

これで、ユーザーがログインしていると考えるようになりました。実際のサーバーを実行し続ける必要はありません。

3
juanpaco