node.js 如何使用 Passport 验证 Supertest 请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14001183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to authenticate Supertest requests with Passport?
提问by Gal Ben-Haim
I'm using Passport.js for authentication (local strategy) and testing with Mocha and Supertest.
我正在使用 Passport.js 进行身份验证(本地策略)并使用 Mocha 和 Supertest 进行测试。
How can I create a session and make authenticated requests with Supertest?
如何使用 Supertest 创建会话并发出经过身份验证的请求?
采纳答案by zemirco
You should use superagentfor that. It is lower level module and used by supertest. Take a look at the section Persisting an agent:
您应该为此使用超级代理。它是较低级别的模块,由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
});
Now you can use user1to make authenticated requests.
现在您可以user1用来发出经过身份验证的请求。
回答by Andy
As zeMirco points out, the underlying superagentmodule supports sessions, automatically maintaining cookies for you. However, it is possible to use the superagent.agent()functionality from supertest, through an undocumented feature.
正如 zeMirco 指出的那样,底层superagent模块支持会话,自动为您维护 cookie。但是,可以使用superagent.agent()从功能supertest通过无证功能。
Simply use require('supertest').agent('url')instead of require('supertest')('url'):
只需使用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();
}
};
};
回答by grub
Try this,
尝试这个,
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();
});
回答by Kevin C.
As an addendum to Andy's answer, in order to have Supertest startup your server for you, you can do it like this:
作为安迪回答的附录,为了让 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();
});
});
});
回答by Dan K.K.
I'm sorry, but neither of suggested solutions doesn't work for me.
对不起,但建议的解决方案都不适用于我。
With supertest.agent()I can't use the appinstance, I'm required to run the server beforehand and specify the http://127.0.0.1:portand moreover I can't use supertest's expectations (assertions), I can't use the supertest-as-promisedlib and so on...
由于supertest.agent()我不能使用app实例,我需要事先运行服务器并指定http://127.0.0.1:port,而且我不能使用 supertest 的期望(断言),我不能使用supertest-as-promisedlib 等等......
The cookiescase won't work for me at all.
这个cookies案子对我根本不起作用。
So, my solution is:
所以,我的解决方案是:
If you are using Passport.js, it utilizes the "Bearer token" mechanism and you can use the following examples in your specs:
如果您使用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();
});
});
});
You may want to have a helper function to authenticate users:
您可能需要一个辅助函数来验证用户身份:
test/auth-helper.js
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);
});
};
Have a productive day!
度过充实的一天!
回答by juanpaco
I'm going to assume that you're using the CookieSession middleware.
我将假设您正在使用 CookieSession 中间件。
As grub mentioned, your goal is to get a cookie value to pass to your request. However, for whatever reason (at least in my testing), supertest won't fire 2 requests in the same test. So, we have to reverse engineer how to get the right cookie value. First, you'll need to require the modules for constructing your cookie:
正如 grub 所提到的,您的目标是获取一个 cookie 值以传递给您的请求。但是,无论出于何种原因(至少在我的测试中),supertest 都不会在同一个测试中触发 2 个请求。因此,我们必须逆向工程如何获得正确的 cookie 值。首先,您需要 require 用于构建 cookie 的模块:
var Cookie = require("express/node_modules/connect/lib/middleware/session/cookie")
, cookieSignature = require("express/node_modules/cookie-signature")
Yes, that's ugly. I put those at the top of my test file.
是的,这很丑陋。我把它们放在我的测试文件的顶部。
Next, we need to construct the cookie value. I put this into a beforeEachfor the tests that would require an authenticated user:
接下来,我们需要构造 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.idwas previously defined in the portion of my beforeEachchain that defined the user I was going to "login". The structure of sessionis how Passport (at least currently) inserts the current user information into your session.
Test.user.id之前在我的beforeEach链中定义了我要“登录”的用户的部分。的结构session是 Passport(至少目前)如何将当前用户信息插入到您的会话中。
The var vallines with "j:"and "s:"are ripped out of the Connect CookieSession middleware that Passport will fallback on if you're using cookie-based sessions. Lastly, we serialize the cookie. I put "session"in there, because that's how I configured my cookie session middleware. Also, App.config.cookieSecretis defined elsewhere, and it must be the secret that you pass to your Express/Connect CookieSession middleware. I stash it into Test.cookieso that I can access it later.
如果您使用基于 cookie 的会话,Passport 将回退的 Connect CookieSession 中间件中删除了var val带有"j:"和的行"s:"。最后,我们序列化cookie。我放在"session"那里,因为这就是我配置 cookie 会话中间件的方式。此外,App.config.cookieSecret在别处定义,它必须是您传递给 Express/Connect CookieSession 中间件的秘密。我把它藏起来,Test.cookie以便我以后可以访问它。
Now, in the actual test, you need to use that cookie. For example, I have the following test:
现在,在实际测试中,您需要使用该 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
}
Notice the call to setwith "cookie"and Test.cookie. That will cause the request to use the cookie we constructed.
注意对setwith"cookie"和的调用Test.cookie。这将导致请求使用我们构建的 cookie。
And now you've faked your app into thinking that user is logged in, and you don't have to keep an actual server running.
现在您已经伪造了您的应用程序,认为用户已登录,并且您不必保持实际服务器的运行。

