Passport & JWT & Google/Facebook Strategy - 如何结合 JWT 和 Google/Facebook Strategy?
Passport & JWT & Google/Facebook Strategy - How do I combine JWT and Google/Facebook Strategy?
此问题适用于熟悉
的任何人
- Node.js
- 快递
- 护照
- 使用护照的 JWT 身份验证(JSON Web 令牌)
- Facebook OAuth2.0 或 Google OAuth2.0
我一直在做一些在线课程并且了解如何做以下两件事:
- 使用 Passport 本地策略 + JWT 令牌进行身份验证
- 使用 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')
时出现以下错误:
我是如何尝试解决问题的:
- 我将 cors 安装到我的 npm 服务器,并将
app.use(cors());
添加到我的 index.js。
- 我试了一下,在 Google 开发者控制台的 "Authorised JavaScript origins" 中添加了“http://localhost:3000”。
这些解决方案都没有解决问题,所以现在我真的很卡。我想使用 axios/ajax 方法,但我不确定如何克服这个 cors 错误。
抱歉发了这么长的信息,但我真的觉得我必须向您提供所有信息,以便您能适当地帮助我。
再次感谢,期待您的来信!
我是这样解决的:
- 在前端(可以是移动应用程序)我向 Google(或 Facebook)发出了登录请求,在用户选择了他的帐户并登录后,我收到了包含 google 的回复授权令牌和基本用户信息。
- 然后我将 google 身份验证令牌发送到后端,我的 API 又向 Google API 发送了一个请求以确认该令牌。 (See step 5)
- 请求成功后,您将获得基本的用户信息和电子邮件。此时,您可以假设用户通过 Google 登录是正确的,因为 google 检查返回正常。
- 然后您只需使用该电子邮件注册或登录用户并创建该 JWT 令牌。
- 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 策略。
此问题适用于熟悉
的任何人- Node.js
- 快递
- 护照
- 使用护照的 JWT 身份验证(JSON Web 令牌)
- Facebook OAuth2.0 或 Google OAuth2.0
我一直在做一些在线课程并且了解如何做以下两件事:
- 使用 Passport 本地策略 + JWT 令牌进行身份验证
- 使用 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')
时出现以下错误:
我是如何尝试解决问题的:
- 我将 cors 安装到我的 npm 服务器,并将
app.use(cors());
添加到我的 index.js。 - 我试了一下,在 Google 开发者控制台的 "Authorised JavaScript origins" 中添加了“http://localhost:3000”。
这些解决方案都没有解决问题,所以现在我真的很卡。我想使用 axios/ajax 方法,但我不确定如何克服这个 cors 错误。
抱歉发了这么长的信息,但我真的觉得我必须向您提供所有信息,以便您能适当地帮助我。
再次感谢,期待您的来信!
我是这样解决的:
- 在前端(可以是移动应用程序)我向 Google(或 Facebook)发出了登录请求,在用户选择了他的帐户并登录后,我收到了包含 google 的回复授权令牌和基本用户信息。
- 然后我将 google 身份验证令牌发送到后端,我的 API 又向 Google API 发送了一个请求以确认该令牌。 (See step 5)
- 请求成功后,您将获得基本的用户信息和电子邮件。此时,您可以假设用户通过 Google 登录是正确的,因为 google 检查返回正常。
- 然后您只需使用该电子邮件注册或登录用户并创建该 JWT 令牌。
- 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 策略。