护照和JWT& Google / Facebook策略 - 如何结合JWT和Google / Facebook策略?

时间:2017-09-24 06:05:05

标签: oauth-2.0 jwt passport.js google-oauth2 facebook-oauth

这个问题适合任何熟悉

的人
  • Node.js的
  • 快速
  • 护照
  • 使用护照进行JWT身份验证(JSON Web令牌)
  • Facebook OAuth2.0或Google OAuth2.0

我一直在做一些在线课程,并了解如何做以下两件事:

  1. 使用Passport本地策略+ JWT令牌进行身份验证
  2. 使用Passport Google / Facebook策略+ Cookie /会话进行身份验证。
  3. 我试图将这两门课程的内容基本结合起来。我想使用Google Strategy + JWT身份验证。我想使用JWT而不是cookie,因为我的应用程序将是一个网络/移动/平板电脑应用程序,我需要从不同的域访问api。

    我对此有两个问题: 要启动Google / facebook OAuth管道,您需要拨打' / auth / facebook'或' / auth / google'。 Oauth流程的工作基本相同,所以当我说' / auth / google'从现在开始,我指的是其中之一。现在我遇到的问题是:在客户端,我是否打电话给' / auth / google'路线与href按钮链接或axios / ajax呼叫?如果我使用href或axios / ajax方法,我仍然会遇到两种解决方案的问题。

    href接近问题: 当我将带有href的<a>代码分配给&#39; / auth / google&#39;身份验证工作完全正常。用户通过Google Auth流程进行推送,他们会登录并使用&#39; / auth / google / callback&#39;路线被召唤。我现在遇到的问题是如何从&#39; / auth / google / callback&#39;中正确地将JWT令牌发送回客户端?

    经过大量的谷歌搜索后,我看到人们只是通过重定向查询参数中的oauth回调将JWT传递回客户端。例如:

    res.redirect(301, `/dashboard?token=${tokenForUser(req.user)}`);
    

    我遇到的问题是,现在我的浏览器历史记录中保存了身份验证功能!我可以注销(破坏localStorage中保存的令牌),然后只需查看我的浏览器URL历史记录,回到查询参数中包含令牌的URL,我会自动再次登录而无需经过谷歌策略!这是一个巨大的安全漏洞,显然是接近它的错误方法。

    axios / ajax方法问题: 现在在我解释这个问题的问题之前,我肯定知道如果我得到这个工作,它将解决我以前的href问题所遇到的所有问题。如果我设法拨打&#39; / google / auth&#39;从axios.get()调用并在响应体中接收JWT,我不会将令牌作为url param发送,并且它不会保存在浏览器历史记录中!完美对吗?这种方法还存在一些问题:(

    尝试拨打axios.get('/auth/google')时出现以下错误:

    enter image description here

    我是如何尝试解决问题的:

    • 我将cors安装到我的npm服务器上,并将app.use(cors());添加到我的index.js中。
    • 我采取了刺,并添加了#34; http://localhost:3000&#34;到#34;授权的JavaScript起源&#34;在Google开发者控制台中。

    这些解决方案都没有解决问题,所以现在我真的感到困惑。我想使用axios / ajax方法,但我不确定如何克服这个错误。

    很抱歉这么长的消息,但我真的觉得我必须给你所有的信息才能帮助我。

    再次感谢,期待收到你的来信!

3 个答案:

答案 0 :(得分:12)

我用这种方式解决了这个问题:

  1. 在前端(可以是移动应用程序)我向Google(或Facebook)发出登录请求,在用户选择了他的帐户并登录后,我得到了包含google身份验证令牌和基本用户信息的回复。
  2. 然后我将google身份验证令牌发送到后端,我的API又向Google API发送了一个请求以确认该令牌。 (See step 5
  3. 成功请求后,您将获得基本的用户信息和电子邮件。此时,您可以假设用户通过Google登录是好的,因为谷歌检查返回它没关系。
  4. 然后,您只需使用该电子邮件注册或登录用户并创建该JWT令牌。
  5. 将令牌返回给您的客户端,并将其用于将来的请求。
  6. 我希望它有所帮助。我实施了多次,它表现得很好。

答案 1 :(得分:1)

尽管答案很好,但我想通过示例添加更多信息。

  • Passport的google / facebook策略基于会话,不建议将用户信息存储在cookie中。所以我们需要先禁用它

要禁用会话,我们需要修改重定向路由器。例如,如果我们具有如下所示的重定向路径 / google / redirect ,则需要传递 {session:false} 对象作为参数。

router.get('/google/redirect', passport.authenticate('google', { session: false }), (req, res)=> {
    console.log(":::::::::: user in the redirect", req.user);
    //GENERATE JWT TOKEN USING USER
    res.send(TOKEN);
})

那么这个用户来自哪里?该用户来自护照的回叫功能。在上一个代码段中,我们添加了 passport.authenticate(....)。此中间线可启动护照的google-strategy回调,该回调与用户打交道。例如

passport.use(
    new GoogleStrategy({
        callbackURL: '/google/redirect',
        clientID: YOUR_GOOGLE_CLIENT_ID
        clientSecret: YOUR_GOOGLE_SECRET_KEY
    }, 
    (accessToken, refreshToken, profile, done)=>{
        console.log('passport callback function fired');

        // FETCH USER FROM DB, IF DOESN'T EXIST CREATE ONE

        done(null, user);

    })
)

就是这样。我们已经成功地将JWT和Google / Facebook策略结合在一起。

答案 2 :(得分:-1)

我找到的解决方案是在弹出窗口(window.open)中执行OAuth流程,它使用预定义的回调函数在成功进行身份验证后将令牌传递给前端。

以下是本教程中的相关代码示例: https://www.sitepoint.com/spa-social-login-google-facebook/

这是从前端调用的预定义回调和初始打开方法:

window.authenticateCallback = function(token) {
  accessToken = token;
};

window.open('/api/authentication/' + provider + '/start');

以下是您的OAuth回调网址应在成功进行身份验证后返回的内容(这是弹出窗口中的最后一步/页面):

<!-- src/public/authenticated.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Authenticated</title>
  </head>
  <body>
    Authenticated successfully.

    <script type="text/javascript">
      window.opener.authenticateCallback('{{token}}');
      window.close();
    </script>
  </body>
</html>

您的令牌现在可用于您的前端预定义回调函数,您可以在其中轻松将其保存在localStorage中。

我想,您可以在同一个窗口中执行OAuth流程(无弹出窗口)并返回一个HTML页面(类似于上面的内容),它只保存令牌并立即将用户重定向到仪表板。

但是,如果您的前端域与api / auth服务器不同,则可能需要使用一次性时间敏感令牌(由生成者生成)从api / auth服务器重定向到前端。您的api / auth服务器),您的前端可以用来调用和接收(使用axios)您的实际令牌。这样您就不会遇到浏览器历史记录安全问题。