护照通过json发送错误

Posted

技术标签:

【中文标题】护照通过json发送错误【英文标题】:passport send error by json 【发布时间】:2015-03-16 23:43:04 【问题描述】:

我正在使用 express + passport 和 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】:

根据护照的当前代码,这可能可以通过传递自定义回调来自己处理所有身份验证结果来实现。此回调在选项之后给出或代替那些。

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() 时传递的任何选项,例如闪烁消息、准备会话和包含经过身份验证的用户的请求等。

    由于给定的选项 passport.authenticate() 从未传递到回调中,因此实际上没有明显的理由同时使用两者。 当我遇到同样的问题(将护照服务与 angular-js POST 请求链接)时,我拒绝考虑使用回调作为适当的解决方案。此回调未记录在案。它甚至看起来都不是很有用,因为它没有通过reqresnext 在回调中传递任何实际请求。因此,使用它毫无意义,我希望它很快就会消失或改变它的行为。

所以第二种方法是试图找出 AngularJS 出现问题的原因。 Passport 正在发送纯文本 Unauthorized 以响应状态代码 401。 AngularJS 试图将其解析为 JSON 并产生语法错误。文本Unauthorized 来自 passprt 结束响应非常简单地调用

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

因此,一个适当的解决方法可能会尝试替换

    http.STATUS_CODES 中的任一文本,尽管这会影响处理进一步的请求,因此不可取 或res.end(),如果res.statusCode 为401,则通过重载方法执行不同的操作。

由于影响任何当前请求,我只尝试了后者。替换的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);
  
);

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

【讨论】:

以上是关于护照通过json发送错误的主要内容,如果未能解决你的问题,请参考以下文章

如何解决护照认证产生的错误

Laravel 护照授权错误

在内部生成 laravel 护照令牌。 401错误未经授权

如何根据护照本地策略发送json数据

使用 nuxt auth 和 laravel 护照登录时出现错误 404

node.js中护照身份验证后如何发送json作为响应