Passport & JWT & Google/Facebook Strategy - 如何结合 JWT 和 Google/Facebook Strategy?

Passport & JWT & Google/Facebook Strategy - How do I combine JWT and Google/Facebook Strategy?

此问题适用于熟悉

的任何人

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

  1. 使用 Passport 本地策略 + JWT 令牌进行身份验证
  2. 使用 Passport 进行身份验证 Google/Facebook 策略 + Cookie/sessions.

我试图将这两门课程的内容基本上结合起来。我想使用 Google 策略 + JWT 身份验证。我想使用 JWT 而不是 cookie,因为我的应用程序将成为 web/mobile/tablet 应用程序,我需要从不同的域访问 api。

我遇到了两个问题: 要启动 Google/facebook OAuth 管道,您需要调用“/auth/facebook”或“/auth/google”。两个 Oauth 流程的工作原理基本相同,所以当我从现在开始说“/auth/google”时,我指的是两者之一。现在我遇到的问题是:在客户端上,我是使用 href 按钮 link 还是 axios/ajax 来调用“/auth/google”路由?如果我使用 href 或 axios/ajax 方法,我仍然会遇到这两种解决方案的问题。

href 方法问题: 当我将带有 href 的 <a> 标记分配给“/auth/google”时,身份验证工作得很好。用户通过 Google 身份验证流程被推送,他们登录并调用 '/auth/google/callback' 路由。我现在遇到的问题是如何正确地将 JWT 令牌从“/auth/google/callback”发送回客户端?

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

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

我遇到的问题是,现在身份验证功能已保存在我的浏览器历史记录中!我可以注销(销毁保存在 localStorage 中的令牌),然后只需查看我的浏览器 url 历史记录,返回到在查询参数中包含令牌的 url,我会自动登录无需通过 Google 策略再次进入!这是一个巨大的安全漏洞,显然是不正确的处理方法。

axios/ajax方法问题: 现在,在我解释这个问题之前,我确信如果我让它工作,它将解决我在之前的 href 问题中遇到的所有问题。如果我设法从 axios.get() 调用中调用 '/google/auth' 并在响应正文中接收到 JWT,我将不会将令牌作为 url 参数发送,它也不会保存在浏览器历史记录中!完美吧?好吧,这种方法仍然存在一些问题:(

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

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

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

抱歉发了这么长的信息,但我真的觉得我必须向您提供所有信息,以便您能适当地帮助我。

再次感谢,期待您的来信!

我是这样解决的:

  1. 在前端(可以是移动应用程序)我向 Google(或 Facebook)发出了登录请求,在用户选择了他的帐户并登录后,我收到了包含 google 的回复授权令牌和基本用户信息。
  2. 然后我将 google 身份验证令牌发送到后端,我的 API 又向 Google API 发送了一个请求以确认该令牌。 (See step 5)
  3. 请求成功后,您将获得基本的用户信息和电子邮件。此时,您可以假设用户通过 Google 登录是正确的,因为 google 检查返回正常。
  4. 然后您只需使用该电子邮件注册或登录用户并创建该 JWT 令牌。
  5. Return 令牌给您的客户,仅用于以后的请求。

希望对您有所帮助。我多次实现了这个,它显示了一个很好的解决方案。

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

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

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

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

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

这是您的 OAuth 回调 URL 应该 return,在成功验证后(这是弹出窗口中的最后一个 step/page):

<!-- 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 中。

不过我想,您可以在同一个 window 然后(没有弹出窗口)和 return 一个 HTML 页面(类似于上面)中执行 OAuth 流程只需保存令牌并立即将用户重定向到仪表板。

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

虽然有很好的答案,但我想通过示例添加更多信息。

  • 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的回调函数。在前面的代码片段中,我们添加了 passport.authenticate(....) 此中间线启动 passport 的 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 策略。