【问题标题】:Get token on the client-side for passport-local authentication在客户端获取令牌以进行本地护照身份验证
【发布时间】:2015-09-10 07:13:16
【问题描述】:

编辑我都尝试了,重定向和不重定向。重定向时,我得到与直接请求 / 相同的结果,当我没有收到时,我收到的是包含 data = Moved Temporarily. Redirecting to / 的对象

鉴于此策略:

var strategy = new LocalStrategy(
{
  session: true
},
function (username, password, done) {
  User.findOne({ username: username }, function(err, user) {
    if (err) { return done(err); }
    if (!user) {
      return done(null, false, { message: 'Incorrect username.' });
    }
    if (user.password !== password) {
      return done(null, false, { message: 'Incorrect password.' });
    }
    return done(null, user);
  });
});

还有这台服务器:

//************ EDIT ****//
function genuuid(req) {
  return "Test UID";
}
//************ EDIT ****//

var app = express();
var router = express.Router();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(passport.initialize());

//************ EDIT ****//
app.use(session({
  genid: function(req) {
    return genuuid() // use UUIDs for session IDs
  },
  secret: "somethingSecret",
  cookie: {maxAge: 60000 },
  resave: true,
  saveUninitialized: false }));
//************ EDIT ****//

passport.use(strategy);

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }));

server = http.createServer(app).listen(port, function(){
  console.log('Express server listening on port ' + app.get('port'));
})

我正在尝试从我的客户端(摩卡测试)获取生成的令牌,如下所示:

it('Login should redirect to home and return a user token', function(done) {
  var postData = querystring.stringify({
    username : user,
    password : password
  });

  var options = {
    uri: 'http://' + hostname + ':' + port +  '/login',
    followRedirect: false
  };

  request.post(options)
    .form(postData)
    .on('response', function(res) {
      res.statusCode.should.equal(302);
    })
    .on('data',function(data) {
      should.exist(data);
      should.fail(0,1,'Test not implemented');
      done();
    })
    .on('error', function(e) {
      should.fail(0,1,'Problem with request: ' + e.message);
  });
});

标题包含

{ 'x-powered-by': 'Express',
  location: '/',
  vary: 'Accept',
  'content-type': 'text/plain; charset=utf-8',
  'content-length': '35',
  date: 'Tue, 08 Sep 2015 19:46:03 GMT',
  connection: 'keep-alive' }

没有 cookie 之类的。我的令牌呢?

【问题讨论】:

  • 你有passport.serializepassport.deserialize函数吗?
  • 我愿意passport.serializeUser(function(user, done) { done(null, user); }); passport.deserializeUser(function(user, done) { done(null, user); });
  • 嗯。在Passport docs(搜索“deserializeUser”)中,deserializeUser 函数似乎将用户从数据库中拉出并返回该对象,而不是调用done,这可能是相关的
  • 此外,它使用特定字段来序列化用户而不是整个对象:passport.serializeUser(function(user, done) { done(null, user.id); }); 请注意,user.id 用于done 的第二个参数.在您的情况下,您可能会使用 user.username
  • 刚刚注意到,这一行:if (!user.password === password) 将始终评估为 false;改为使用if (user.password !== password)

标签: node.js passport.js passport-local


【解决方案1】:

尝试使用会话中间件进行会话,例如express-session

var session = require('express-session');
// Code to set up your app
var app = express();

// Make sure to replace "somethingSecret" with your own secret value
app.use(session({secret: "somethingSecret", resave: true, saveUnitialized: false}));

我写了一个与你提供的非常接近的应用程序,并且看到了同样的问题,这对我来说很奇怪,因为我以前多次使用过快递和护照。当我意识到我没有使用任何会话中间件时,我添加了 express-session 中间件和 voila; set-cookie 标头。

但请注意,此代码实际上尚未准备好投入生产。来自express-session 存储库:

警告 默认的服务器端会话存储 MemoryStore 故意不是为生产环境设计的。它在大多数情况下都会泄漏内存,不会扩展到单个进程之外,并且适用于调试和开发。

有关商店列表,请参阅compatible session stores

[编辑]

使用此代码(用户被存根以始终返回相同的值):

var bodyParser = require('body-parser');
var express = require('express');
var http = require('http');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var session = require('express-session');

// Stub of User schema for testing
var User = {
    findOne: function(user, callback) {
        callback(null, {
            id: 1234,
            username: user.username,
            password: 'foo'
        });
    },
    findById: function(id, callback) {
        callback(null, {
            id: 1234,
            username: 'user',
            password: 'foo'
        });
    }
};

var strategy = new LocalStrategy(
{
  session: true
},
function (username, password, done) {
  User.findOne({ username: username }, function(err, user) {
    if (err) { return done(err); }
    if (!user) {
      return done(null, false, { message: 'Incorrect username.' });
    }
    if (user.password !== password) {
      return done(null, false, { message: 'Incorrect password.' });
    }
    return done(null, user);
  });
});

function genuuid(req) {
  return "Test UID";
}

var app = express();
var router = express.Router();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(passport.initialize());

app.use(session({
  genid: function(req) {
    return genuuid() // use UUIDs for session IDs
  },
  secret: "somethingSecret",
  cookie: {maxAge: 60000 },
  resave: true,
  saveUninitialized: false }));
  
passport.use(strategy);

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});
  
app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }));

server = http.createServer(app).listen(51015, function(){
  console.log('Express server listening on port ' + app.get('port'));
});

运行测试:

var should = require('should');
var assert = require('assert');
var request = require('request');
var querystring = require('querystring');

it('Login should redirect to home and return a user token', function(done) {
  var postData = querystring.stringify({
    username : 'user',
    password : 'foo'
  });

  var options = {
    uri: 'http://' + '127.0.0.1' + ':' + '51015' +  '/login',
    followRedirect: false
  };

  request.post(options)
    .form(postData)
    .on('response', function(res) {
      console.log(res.headers);
      res.statusCode.should.equal(302);
    })
    .on('data',function(data) {
      should.exist(data);
      should.fail(0,1,'Test not implemented');
      done();
    })
    .on('error', function(e) {
      should.fail(0,1,'Problem with request: ' + e.message);
  });
});

给出以下输出;请注意包含 set-cookie 标头:

mocha


{ 'x-powered-by': 'Express',
  location: '/',
  vary: 'Accept',
  'content-type': 'text/plain; charset=utf-8',
  'content-length': '35',
  'set-cookie': [ 'connect.sid=s%3ATest%20UID.NC0hY3rYGMdnN560ewpf%2FaJbO%2BNd9M7QLz3gnse0eLs; Path=/; Expires=Wed, 09 Sep 2015 13:08:06 GMT; HttpOnly' ],
  date: 'Wed, 09 Sep 2015 13:07:06 GMT',
  connection: 'close' }
  1) Login should redirect to home and return a user token

  0 passing (69ms)
  1 failing

  1)  Login should redirect to home and return a user token:

      Uncaught AssertionError: Test not implemented

除了删除的 User 架构和硬编码的配置值之外,我的代码应该和你的一样,所以我有点不知所措,因为你没有得到 set-cookie 标头。

您是否使用任何其他可能影响会话或 cookie 的 express 中间件?

[编辑 2]

问题在于(在您的repository 中)您正在将session 中间件添加到与server.listen 执行的范围不同的范围内,因此对app 所做的更改实际上不会生效.

与其让服务器在测试组之前开始监听,不如让它为每个测试启动一次,并立即将所有需要的参数传递给它。我已向您的存储库提交了pull request,其中详细说明了我可能如何执行此操作,因为它不是少量代码,因此在这里粘贴并不理想。 p>

请花时间阅读并理解这些更改,因为我只关心发送会话令牌,我不保证其他功能是否会受到这些更改的影响。

【讨论】:

  • 我明天试试。实际上,我正在制作某种策略工厂,旨在为任何给定策略添加一些额外的功能,而我只是以本地策略为起点进行测试......
  • 我尝试了 EDIT cmets 之间的内容,但仍然没有运气 genuuid() 在每个请求上都被访问,但我在响应中没有得到任何 cookie。也许这与测试本身有关?顺便说一句,谢谢你的帮助。这开始有点令人沮丧。
  • @LuisSieira 我已经编辑了我的答案以包含我正在工作的代码。我不认为这是测试的问题。我几乎完全复制了您的代码,但我没有看到问题。我能想到的唯一事情是其他一些干扰sessionpassport 的中间件,或者可能是您的User 架构的问题,但鉴于正在调用generateuuid 函数,这似乎不太可能
  • @LuisSieira 是否有可以在问题中链接到的开源存储库?如果潜在的回答者可以看到您的服务器运行的确切上下文,那将非常有帮助。
  • 当然,这里是github.com/sieira/sereno,但它比问题复杂一点
猜你喜欢
  • 2013-06-28
  • 2019-05-21
  • 2020-04-19
  • 2012-10-18
  • 1970-01-01
  • 2014-03-17
  • 1970-01-01
  • 2017-08-12
  • 2020-03-25
相关资源
最近更新 更多