使用 Passport + Facebook + Express + create-react-app + React-Router + 代理进行身份验证

Posted

技术标签:

【中文标题】使用 Passport + Facebook + Express + create-react-app + React-Router + 代理进行身份验证【英文标题】:Authentication with Passport + Facebook + Express + create-react-app + React-Router + proxy 【发布时间】:2017-12-02 12:59:16 【问题描述】:

TLDR:如何从我的 React 应用程序中的页面启动 Facebook Auth 流程?

我发现很多帖子都涉及到我在这篇帖子标题中列出的大部分项目,但不是全部。而且我非常接近于让这个工作,但一定有一些我遗漏的东西。

我的应用包含一个使用 react-router 进行路由的 create-react-app 前端。我在我的开发环境中的端口 51000 上运行它。在 package.json 中,我使用“代理”将其他路由重定向到我的 express 服务器,在端口 51001 上运行。这通常适用于在我的 React 组件中发出访问服务器的请求。例如:

axios.get('/api/some-stuff')

在我的 React 组件中调用时,这将成功访问我的 Express 服务器。

我想确保我的后端路由经过身份验证,并且我选择通过 passport-facebook 使用 Facebook 身份验证。我已经设置了这个,就像我看到的许多在线教程一样。例如,我的快速服务器上有一条名为“/auth/facebook”的路由。如果我去 localhost:51001/auth/facebook,它会将我重定向到 facebook 以登录,然后将我重定向回我给它的一些路线。因此该流程按预期工作。

我遇到的具体问题是让 React 成功启动并完成触发身份验证的 api 调用。我尝试了两种方法。

方法一:通过ajax调用路由

我在 componentDidMount 中调用了以下内容:

axios.get('/auth/facebook')

这成功地访问了我的快速服务器,但随后立即在浏览器控制台中生成以下错误:

XMLHttpRequest 无法加载 https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%…2Flocalhost%3A51000%2Fauth%2Ffacebook%2Fcallback&client_id=XYZ。重定向自 'https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%…2Flocalhost%3A51000%2Fauth%2Ffacebook%2Fcallback&client_id=XYZ' 'https://www.facebook.com/login.php?skip_api_login=1&api_key=XYZ…_&display=page&locale=en_US&logger_id=7f30b5a1-2ad1-dc31-f08b-70d3cfdd55fa' 已被 CORS 策略阻止:没有“访问控制允许来源” 请求的资源上存在标头。起源 'http://localhost:51000' 因此不允许访问。

**方法二:在浏览器中去路由**

我尝试过的另一件事(我在所有教程中都看到过)是向我的一个页面添加一个链接,该页面只是导航到身份验证路径。例如:

<a href="/auth/facebook">Login with Facebook</a>

但是,当我单击此按钮时,我只会看到 http://localhost:51000/auth/facebook,或者只是我的 React 应用程序中的一个空白页面。我的代理没有启动,当我在浏览器中转到此路由时,我在 Express 服务器上看不到任何活动,即使它不是我在 react-router 中定义的路由。

所以我有点卡在这里。单击该标记是否应该触发该路由以针对我的 Express 服务器触发?有没有办法告诉 react-router 忽略某些路由,以便将它们重定向到我的快速服务器?这在进行 AJAX 调用时似乎工作正常,但如果我转到 localhost:51000/not/a/route,这不会导致请求被重定向到 Express。它只是加载一个没有内容的反应页面。

感谢任何帮助。

谢谢,

-丹

编辑

所以我现在有点像这样,虽然我完全不相信这是“正确”的做事方式。

在我的 react 应用程序(召回在端口 51000 上运行)中,我有以下链接:

<a href="http://localhost:51001/auth/facebook">Facebook Login</a>

请注意,这直接指向我的 API 服务器,而不是反应路由。导航到此链接会点击快速服务器,并立即重定向到 Facebook。登录重定向回我的 Express facebook 回调,它本身重定向到 http://localhost:51000/somePage,现在又回到了我的 react 应用程序。

理想情况下,该标签将转到 /api/auth/facebook,而不是硬编码以转到不同的 URL/端口。如果/当我弄清楚如何让 react-router 通过而不是将其视为需要加载的页面时,我将更新此问题。

编辑 2

我愿意接受其他人告诉我,但我认为我目前的方法实际上非常好。我考虑了事情在生产中的表现。我将在 www.example.com 上拥有我的反应站点,并通过 api.example.com 访问我的快速服务器。我的 Facebook 登录链接将是“api.example.com/auth/facebook”。回调,假设认证成功,将重定向到“www.example.com/some/route”。我认为跳转到“api” URL 来执行登录是合理的。最终,尝试让 react-router 忽略某些路由是没有意义的,因为我所有的 api 调用都将指向明确的路由。

我意识到我并没有为其他人提供一个完整有用的解决方案。将所有内容放在一起后,我将包含一个指向包含此登录流程的存储库的链接,以防其他人发现它有帮助。

** 编辑 3 **

这里是我的项目的链接。让整个项目运行起来并非易事,但只有少数几个文件与身份验证流程相关联。

你可以在这里查看 repo:https://github.com/dan-goyette/Portfolio

用于此的 Express 服务器路由器在这里:

https://github.com/dan-goyette/Portfolio/blob/master/portfolio-server/src/Routing/auth.js

在 UI 中,我正在使用此组件触发对 express 服务器的调用:

https://github.com/dan-goyette/Portfolio/blob/75ca9326e6227d0601cdfa4c0cece672bd347302/portfolio-ui/src/Components/SocialMenuButton/SocialMenuButton.js

您可以在右上角的按钮https://www.dan-goyette.com/home 上看到它。

【问题讨论】:

有没有找到允许redux-thunk 流动的解决方案?我不希望这部分使用 href 我不使用 redux,所以我不确定这需要什么,但我正在编辑我的帖子以包含指向我的项目的链接,以显示我的解决方案。 拜托了! Redux 并没有改变我们共同的问题。我正要解决你的href 包裹着按钮移动。您是否有机会找到一种使用 axios 进行 GET 调用并且仍然调用回调的方法?这将是我现有代码和预期用途的最佳选择...... 【参考方案1】:

我也遇到了这个问题 - 更改 CRA 代理配置似乎可以解决问题:

"proxy": 
   "/api": 
      "target": "http://localhost:3001/"
   

OAuth 链接位于/api/auth/foo,CRA 应用位于localhost:3000,快递应用位于localhost:3001

【讨论】:

我已经在passport-twitter 上尝试过这个技巧来解决类似的问题,但无济于事【参考方案2】:

我今天遇到了同样的问题并通过不使用create-react-app的代理解决了它,而是在我的后端设置了一个代理到create-react-app

在我的快递应用程序的结束,我有

 // all routes above

 if (env.isDevelopment()) 
   const proxy = require('express-http-proxy')
   app.use('/*', proxy('http://localhost:3000'))
  else 
   // probably serve up build version in production
 

请记住关闭客户端包 json 中的代理,否则可能会导致无限代理循环或其他问题。

【讨论】:

我用这种方法得到了bundle.js:1 Uncaught SyntaxError: Unexpected token &lt;。直接访问时,CRA 应用程序很好。这是我的节点/快递代码:gist.github.com/bvodola/5640b237509dc061f754df2ad0812cee 听起来您的服务器正在为 js 资源提供 index.html 文件,&lt;&lt;!doctype 的开头。您真正的 index.html 正在请求 bundle.js ,而不是 js 文件,它再次获取索引。这似乎是一个过于渴望的 app.use。我会把我的整个代码块放在最后,这应该会有所帮助 您好,请问这种方法是否也适用于会话数据?我的 express 后端设置为 passport-facebook,身份验证在 express 端工作,我可以将其重定向回我的前端路由。有没有一种方法可以在身份验证后重定向时,可以保留会话数据(登录用户)和/或在 redux 中获取登录用户数据存储?真的卡在这个了! 只要你总是在同一个端口上,这应该与会话数据没有任何关系。您的会话 ID 应该保持不变。如果您遇到会话问题,我会寻找其他地方。【参考方案3】:

编辑:我之前的回答与问题无关,也没有解决。在我的情况下,整个事情是由 CLI 生成的 index.js 中的 registerServiceWorker 引起的。只需删除它,一切都会正常运行。

//Remove this lines from index.js
import registerServiceWorker from './registerServiceWorker'

registerServiceWorker();

【讨论】:

这似乎与问题的原因无关。【参考方案4】:

您可以将您的 create react app localhost 服务器添加到 web api 通过转到 console.developers.google.com 并将 create-react-app localhost 添加到“授权的 javascript 来源”和“授权的重定向 URI”。

【讨论】:

【参考方案5】:

我通过在 Facebook 登录产品部分的 Facebook 开发人员设置中使用“有效 OAuth 重定向 URI”字段解决了这个问题,例如,http://your-domain.loc:5000/auth/facebook

Facebook Auth 按钮应该是:

<a href="http://your-domain.loc:5000/auth/facebook">Login with Facebook</a>

你应该把你的 facebook 重定向 URL 放在那里。我的示例中还有一件事:我将 3000 端口用于本地节点服务器,将 5000 端口用于我的应用程序上的 API 请求。

我使用/etc/hosts 来使用我的域,而不是localhost

127.0.0.1   your-domain.loc

为我工作。

此外,关于 GitHub 资源的其他讨论正在进行中 - https://github.com/facebook/create-react-app/issues/3502

【讨论】:

【参考方案6】:

在 Facebook 开发者设置中添加localhost(Facebook 登录)

Facebook 登录仅适用于 https,您应该设置 你的 localhost 与 https 一起工作

【讨论】:

以上是关于使用 Passport + Facebook + Express + create-react-app + React-Router + 代理进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Passportjs Facebook 登录流程(passport-facebook vs passport-token)

如何在没有会话的情况下整合passport-facebook和jwt?

使用 Passport 和 ExpressJS 进行 Facebook 身份验证 - 为啥不调用验证回调?

使用 Passport 通过 Facebook 进行身份验证不起作用

Passport-facebook没有收到电子邮件[重复]

Passport.js:passport-facebook-token 策略,通过 JS SDK 登录然后验证护照?