如何为 passportjs 使用 jquery/ajax 数据

Posted

技术标签:

【中文标题】如何为 passportjs 使用 jquery/ajax 数据【英文标题】:How to use jquery/ajax data for passportjs 【发布时间】:2014-11-19 03:06:22 【问题描述】:

如果我使用表单字段action="/login", method="post" 发送登录请求,它就可以正常工作。类似于可用的代码here 或here。

但是,如果我使用jquery/ajax 发送相同的信息,那么护照似乎不起作用。没有通过护照进行实际登录,但 ajax 调用给出了误导性的成功消息。

以下内容不起作用。虽然我收到“登录成功”消息,但登录并没有真正发生。

$('#login_button').click(function () 

    var email = $('#email').val();
    var password = $('#password').val();
    alert ('email/pass:' + email + ", " + password);

    $.ajax(
        type: "POST",
        url: "/login",
        data:  email: email , password: password ,
        dataType: 'html'
    )
            .done(function () 
                console.log("http request succeeded");
                alert("login success");
            );
);

我需要使用ajax 方法,这样我才能在成功登录后在客户端做一些有用的事情。例如。开始socket.io

请帮忙。我修改后的代码可以在这里找到:my-modified-code

【问题讨论】:

不确定但试试data: $.param( email: email , password: password ) 而不是data: email: email , password: password 您没有检查 AJAX 请求返回的内容。它可能会返回一条错误消息,帮助您诊断问题所在。现在你所做的只是在请求完成时显示一条消息,而不是实际处理返回的内容。 @T00rk 我现在试过了。不工作。此外,我尝试了data: JSON.stringify( "username": "bob", "password": "secret")contentType : 'application/json'dataType: "json" 等的各种组合。我怀疑问题可能出在passport.js @RamsaySmith 我正在检查 Chrome 的“网络”,在响应中,我没有发现任何错误。我得到的状态是“302 临时移动”。 【参考方案1】:

我尝试了您的代码,并且 Passport 可以正常工作。我做了“本地注册”、“注销”,然后是“本地登录”,并成功通过了身份验证,但在 UI 中没有任何指示。

这与您所说的 302 有关 - 服务器回复 302 因为您已定义 successRedirect : '/profile',然后 jQuery 遵循重定向并接收到它无法解析的 HTML,因为它需要 JSON。而且由于您没有在 $.ajax 调用中定义 .fail() 回调,因此您看不到它。

会话很好,但可以通过手动转到 /profile 来查看。

当您使用常规 HTML 表单登录时,浏览器将发送单个 HTTP 请求并根据响应执行操作(例如,呈现 HTML 页面,或者如果是 302 则执行重定向)。当您调用 $.ajax 时,同样的情况会发生,但在不同的上下文中 - AJAX 调用遵循重定向,因为它发出了请求,但浏览器没有。

您应该为 AJAX 和 HTML 登录使用单独的路由,或者使用 custom callback 并根据 req.accepts() 确定要返回的内容。

单独的路线可以是例如。

// AJAX logins to this URL, redirect on client side using
// window.location.href if login succeeds
app.post('/login/ajax', passport.authenticate('local-login'));

// HTTP login form send to this URL
app.post('/login', passport.authenticate('local-login', 
  successRedirect : '/profile',
  failureRedirect : '/login',
  failureFlash : true
));

自定义回调可能是这样的(未测试):

app.post('/login', function(req, res, next) 
  passport.authenticate('local-login', function(err, user, info) 
    switch (req.accepts('html', 'json')) 
      case 'html':
        if (err)  return next(err); 
        if (!user)  return res.redirect('/login'); 
        req.logIn(user, function(err) 
          if (err)  return next(err); 
          return res.redirect('/profile');
        );
        break;
      case 'json':
        if (err)   return next(err); 
        if (!user)  return res.status(401).send("ok": false); 
        req.logIn(user, function(err) 
          if (err)  return res.status(401).send("ok": false); 
          return res.send("ok": true);
        );
        break;
      default:
        res.status(406).send();
    
  )(req, res, next);    
);

【讨论】:

感谢您试用代码。直到最后一段我才明白你的回答。我没想到 AJAX 会重定向,但 Express 路由会重定向(当没有 AJAX 时它会这样做,只是形式)。请详细说明“用于 AJAX 和 HTML 登录的单独路由”...我尝试单独实现自定义回调,但没有奏效(我阅读了它,但不明白 req.accepts()...我一直在尝试,但是我不明白。 另外,在使用 AJAX 时,我注意到控制台中的 GET /profile 200 8msmorgan('dev') );这意味着它是一个成功的登录,/profile 确实被调用了。但是为什么重定向没有在客户端实现呢?没有 AJAX 时也能正常工作。 更新了答案,希望能回答问题。 非常非常有用。非常感谢!两种方法都可以完美运行。结束报价需要小幅更改 - 从 req.accepts('html, json')req.accepts('html', 'json')。请提出一个单独的问题:您为什么在app.post('/login', function(req, res, next) 中使用next ... 什么时候使用next 或不使用next 是个好主意? 谢谢,更新了req.accepts 部分(来自 Express 3)。关于next - 检查例如。 this answer 给出了很好的解释。【参考方案2】:

如果不查看您的服务器端代码以及您使用的是哪种护照策略,任何人都无法判断。例如,本地策略的 sn-p 如下所示:

function Strategy(options, verify) 
  // snip 
  this._usernameField = options.usernameField || 'username';
  this._passwordField = options.passwordField || 'password';
  // snip

// snip

Strategy.prototype.authenticate = function(req, options) 
  options = options || ;
  var username = lookup(req.body, this._usernameField) || lookup(req.query, this._usernameField);
  var password = lookup(req.body, this._passwordField) || lookup(req.query, this._passwordField);
  // snip

您从 jQuery 传递的字段需要与您在服务器端的配置方式以及该策略正在寻找的内容相匹配。在这种情况下,如果您使用本地策略而不配置用户名和密码,它会查找要在 req.body 或 req.query 中传递的用户名和护照字段。

所以不 - 电子邮件将不起作用。但是,您可以通过在选项对象中传递一个覆盖默认用户名的字段来实例化策略,例如,


   username: 'email'

我以前用它通过 jQuery 验证护照:

  var login = function (un, pwd) 

        $.ajax(
            type: "POST",
            dataType: 'json',
            data:  "email": un.val(), "password": pwd.val() ,
            url: "/rest/login/?format=json",
            success: function (data) 
                window.location.href = '/somewhereElse'
            
        );
    

我怀疑你的 dataType 需要是 'json' 而不是 'html'

【讨论】:

感谢您的回复。但是我提供了指向我的整个代码、服务器和客户端的链接(单击最后一行:my-modified-code)。此外,在我的代码中,如果您只是恢复通过表单字段提交,请取消注释两行.. (1) <form action="/login" method="post"> 和 (2) </form> in login.ejs ... 它工作得很好。请克隆它并尝试。 我试过dataType: 'json'。不工作。此外,这不是电子邮件与用户名的问题。当我尝试使用用户名使用相同的jquery/ajax 时,在此处修改代码(包含 ajax 调用)后,我遇到了完全相同的问题:github.com/maxdow/passport-local/tree/master/examples/express4 尝试在这方面达到顶峰,这对我来说也很沮丧:***.com/questions/21855650/…【参考方案3】:

也许这是一个比埋在 cmets 更好的地方。我几个月前经历过类似的事情,并在这里回答了我自己的问题:

Passport authenticate callback is not passed req and res

基本上我能够让它工作,并使用签名处理帖子:req,res,next 和在该处理程序内部,您使用所需的策略调用 passport.authenticate。 passport.authenticate 不应该是(或者至少在我的情况下不会充当)路由的处理程序

server.post(route, function(req, res, next)

    passport.authenticate('local', function(err, user) 

    )

)

我一直无法让 passReqToCallback 选项起作用。

【讨论】:

以上是关于如何为 passportjs 使用 jquery/ajax 数据的主要内容,如果未能解决你的问题,请参考以下文章

如何为 css 倾斜过渡添加 jquery 回退?

如何为 JQUERY 数据表返回 JSON 数据?

jQuery validate:如何为正则表达式验证添加规则?

如何为 jQuery DataTables 获取 JSON 的某些部分

您如何为用于 jquery 编码的菜单栏正确编写 CSS 代码?

如何为我的 jquery validate 自定义函数制作一条中心消息?