护照由json发送错误

时间:2015-01-19 01:11:48

标签: json angularjs node.js passport.js

我正在制作带快递+护照和angularJS的应用程序;我希望能够通过json发送护照产生的任何错误(例如用户名或不提供电子邮件),这样我的angularJS应用程序就可以在json响应中收到这些错误。现在更具体地说,我想对我的注册POST方法进行json响应,输出任何错误。我试图为自己做这个,我在网上搜索和堆栈溢出我无法解决这个问题!

这是我的用户路由文件在express:

var express = require('express');
var router = express.Router();
var isAuthenticated = require('../config/isAuthenticated');

module.exports = function(passport){
    router.get('/loggedin', function(req, res){
        res.send(req.isAuthenticated() ? req.user : '0');

    });

    router.post('/signup', passport.authenticate('local-signup', {
        successRedirect : '/',
        failureRedirect : '/signup',
        failureFlash: true
    }));

    router.post('/login', passport.authenticate('local-login'), function(req, res){
        res.send(req.user);
    });


    router.post('/signout', function(req,res){
        req.logout();
        res.json({redirect: '/'});
    });

    router.get('/authtest', isAuthenticated, function(req, res){
        res.render('authtest', {user: req.user});
    });

    return router;
};

这是我的护照注册策略:

passport.use('local-signup', new LocalStrategy({
    usernameField : 'username',
    passwordField : 'password',
    passReqToCallback : true
},
function(req, username, password, done){
    process.nextTick(function(){
        User.findOne({'local.username' : username}, function(err, user){
            if(err) return done(err); 
            if (user) { //username already exists
                return done(null, false, {message: 'Username already exists'});     
            } else if(!req.body.email) { //no email address provided
                return done(null, false, {message: 'You must provide an email address!'});
            } else {
                var newUser = new User();
                newUser.local.username = username;
                newUser.generateHash(password, function(err, hash){
                    if(err) return done(err);
                    newUser.local.password = hash;
                });
                newUser.email = req.body.email;
                newUser.servers = [];
                newUser.save(function(err){
                    if(err) throw err;
                    return done(null, newUser);
                }); 
            };
        });
    });
}
));

我知道现在看着我的代码看起来我自己都没有试过解决这个问题,但这只是我最新的工作代码;过去几天我一直被困在这里!

非常感谢任何帮助:)

1 个答案:

答案 0 :(得分:2)

根据目前的护照代码,这可能是通过传递自定义回调来自己处理所有真实结果而实现的。这个回调是在选项之后给出的,而不是那些。

passport( "local-signup", { ... }, callbackFn );

passport( "local-login", callbackFn );

此回调用于尝试验证的所有结果情况。因此,它会在处理错误时调用:

callbackFn( err )

如果(所有已配置)身份验证失败,则使用

进行调用
callbackFn( null, false, challenge(s), status(es) )

成功通过身份验证的用户后,将调用回调:

callbackFn( null, user, infos )

可选择由策略提供infos

现在来到底层: 情况passport.authenticate()跳过正常处理但立即调用提供的回调以关注其余部分。这包括处理呼叫passport.authenticate()时传递的任何选项,如闪烁消息,准备会话和请求包含经过身份验证的用户等。

  1. 由于给定passport.authenticate()的选项永远不会传递给回调,因此实际上没有明显的理由同时使用它们。
  2. 当我遇到同样的问题(将passport-service与angular-js POST请求联系起来)时,我拒绝考虑使用回调作为正确的解决方案。此回调未记录。它并不是非常有用,因为它没有通过reqresnext来传递回调中的任何实际请求。因此,使用它几乎没有任何意义,我希望它很快就会消失或者改变它的行为。
  3. 所以第二种方法是试图找出AngularJS中存在问题的原因。 Passport正在发送纯文本Unauthorized以回复状态代码401。 AngularJS试图将其解析为JSON并产生语法错误。文本Unauthorized来自passprt结束响应非常简单地通过调用

    res.statusCode = 401;
    res.end(http.STATUS_CODES[res.statusCode]);
    

    因此,正确的解决方法可能会尝试替换

    1. http.STATUS_CODES中的任何一个文字虽然这对处理更多请求产生了影响,因此并不是优先考虑的
    2. 如果res.end()为401,
    3. res.statusCode通过重载方法采取不同的行为。
    4. 由于影响了当前的任何请求,我尝试了后者。替换res.end()可能用于发送您想要的任何文本:

      router.post('/login',
        function(req, res, next) {
          var _end = res.end;
          res.end = function() {
            if (res.statusCode === 401) {
              return _end('{"status":"Unauthorized"}');
            }
            return _end.apply(this, arguments);
          };
          next();
        },
        passport.authenticate('local-login'),
        function(req, res) {
          res.send(req.user);
        }
      );
      

      或者,替换方法可能会在内容类型上添加以前缺少的响应头信息,因为这实际上导致AngularJS处理中的问题,默认情况下响应为JSON

      router.post('/login',
        function(req, res, next) {
          var _end = res.end;
          res.end = function() {
            if (res.statusCode === 401) {
              res.set("Content-Type", "text/plain");
            }
            return _end.apply(this, arguments);
          };
          next();
        },
        passport.authenticate('local-login'),
        function(req, res) {
          res.send(req.user);
        }
      );
      

      最后,任何一种方法都只是一种解决方法。我认为护照需要修改这个恼人的限制。