网页网站您现在的位置是:首页 > 博客日志 > 网页网站

如何为静态网页添加 OAuth 登录?

<a href='mailto:'>微wx笑</a>的头像微wx笑 2022-07-15网页网站 5 0关键字: OAuth  登录  

在静态生成的站点上使用 Cloudflare Workers 进行 OAuth2021/11/14更新: 这篇文章出现在 Hacker News 上并引发了很多讨论。我还在结论中添加了几句话来解决供应商锁定问题。

在静态生成的站点上使用 Cloudflare Workers 进行 OAuth

2021/11/14

更新: 这篇文章出现在 Hacker News 上并引发了很多讨论。我还在结论中添加了几句话来解决供应商锁定问题。tKI无知

介绍

最近我想在这个网站上设置一些按钮,让用户通过 OAuth 注册时事通讯。如果您想跳过所有介绍/背景信息,请查看 源代码 并直接跳转到 实现。这背后的动机是因为我听了 tldr.tech 的 Dan 的播客,他在其中强调了轻松注册过程的重要性。由于 Dan 比我更有经验(他的时事通讯有超过 10 万订阅者),而且这个建议听起来很合理,我决定着手实施它。您可以在下面看到我正在谈论的示例(这是我实际使用的,并且会订阅我的时事通讯)。tKI无知

背景

作为背景知识,该站点是静态生成的 (SG),这意味着所有页面都是预先构建的,然后转移到它们的存储位置。如果您不熟悉静态站点生成的工作原理,我不会详细介绍,但一个简单的解释是您生成了一堆文件(html、js、css),这些文件是导入到这些文件中的网页或组件网页。这是最简单的网站类型,与动态生成 (DG) 网站不同,后者的网页是根据请求使用最新数据构建的。tKI无知

使用现代工具,您不需要服务器来托管您的 SG 站点,因为您可以将其上传到许多不同的服务之一(Netlify、S3 存储桶、Github 页面)并让它们免费为您托管。这很棒!而且由于我们可以在浏览器中运行 JavaScript (JS),人们可能会认为实现 OAuth 注册相对来说是微不足道的;毕竟,您只需要编写一个将用户重定向到 OAuth 页面的获取请求,然后再编写一个将他们的电子邮件发送到选择的时事通讯服务以进行注册的请求。好吧,问题在于,为了执行该过程的第二步,需要访问需要身份验证的 API 端点(API 密钥)。这本质上是一个密码,而不是您想在前端公开并让每个人都可以访问的东西。tKI无知

这是一只鸟!是飞机!这是一个无服务器功能!

过去,可以设置一个虚拟专用服务器 (VPS),在其上运行一个 HTTP 服务器以公开一个端点,然后让该端点执行向新闻通讯提供者服务注册用户。维护服务器有点痛苦,所以这里有无服务器功能来拯救!虽然有点用词不当(肯定有服务器),但无服务器功能非常棒,因为您无需维护服务器即可使用它们。由于我已经在使用 Cloudflare 来代理网站,我认为 Cloudflare Workers 将是一个很好的解决方案。我对它们了解不多,所以这里有一些细分。tKI无知

Cloudflare 工作者

Cloudflare Worker (CW) 的核心只是让您可以访问类似于 Node.js 环境的东西。“Worker 运行时”构建在 Chrome V8 引擎之上,它运行您在浏览器或 Node.js 中编写的 JS 代码。有一些特定于平台的差异,主要限于 您可用的 API 调用。如果你会写 JS,你可以在 5 分钟内弄清楚如何使用这些。tKI无知

我发现比较复杂的是使用workers时的实际流程,所以我画了两张图来说明区别。tKI无知

图片显示了典型的静态站点服务设计,左侧的客户端浏览器从右侧的服务器请求 home.html。

第一个很容易理解。您的浏览器向服务器发出文件请求,服务器提供该文件。这种解释抛弃了所有必须在其间发生的网络,但这超出了本文的范围。tKI无知

显示通过 Cloudflare 代理的静态站点架构的图像。 客户端浏览器在左侧,从中间的 Cloudflare 请求文件,它检查是否必须运行工作程序,然后检查文件是否被缓存。 如果它没有被缓存,它会从右边的服务器请求它。 如果它被缓存,它会将文件返回给客户端。

所以这个有点复杂。当您使用 Cloudflare 代理您的站点时,它们的边缘基础设施位于客户端(您的浏览器)和您的服务器之间。他们使用 DNS 执行此操作。由于使用它们需要更改为您的域的名称服务器,因此它们可以控制您的域指向的 IP 地址。出于所有意图和目的,我们可以将上图中的 Cloudflare 块视为 Cloudflare 拥有和运营的一个服务器或一组服务器。tKI无知

当请求从客户端浏览器到达 Cloudflare 块时,Cloudflare 将检查请求的 URL 是否与任何工作路由匹配。如果是这样,它将运行工作程序并最终返回其结果。还有一些缓存检查过程正在进行常规请求,但这实际上只是检查请求的文件是否被缓存,然后返回它或访问您的服务器以检索它并返回它。tKI无知

使用 Worker 实现 OAuth

在我们开始实施之前,我想提一下,您需要在相应的平台上注册以获取允许您使用 OAuth 注册用户的 API 密钥。专业提示:如果您要注册 Google,请不要包含徽标,因为这需要获得批准并且可能需要很长时间。tKI无知

我用于实现的很多代码都取自 这个 repotKI无知

该 repo 中的原始工作流看起来是这样的,不包括开头的 CORS 处理,可以概括为:当用户在第一步中单击链接时,它向工作人员发送 OPTIONs 请求,工作人员返回 CORS标头,然后开始下面的过程。tKI无知

  1. 用户单击指向 CW 路线的链接tKI无知

  2. CW 检查请求类型 (GET) 并使用服务的客户端密钥/ID(API 密钥)获取 OAuth URLtKI无知

  3. OAuth 请求返回 OAuth 权限授予页面的 URL(针对用户)tKI无知

  4. CW 返回带有重定向的响应,将用户导航到 OAuth 页面tKI无知

  5. 用户接受权限tKI无知

  6. 用户被重定向到您在使用服务注册 OAuth 访问时设置的“成功”页面tKI无知

  7. 成功页面 JS 在页面加载时执行,检查 URL 中的 OAuth 身份验证代码,并向 CW 发送 POST 请求tKI无知

  8. CW 检查请求类型 (POST) 并向 OAuth 服务 API 发送请求,请求用户的电子邮件tKI无知

  9. 请求与用户的电子邮件返回和另一个请求发送到时事通讯服务 API 注册该电子邮件tKI无知

整个过程中最困难的部分只是违反直觉的事实,即您的注册请求是从成功页面发送的,而不是从 OAuth 过程开始的页面发送的。您可以在源代码中看到为 Github OAuth 处理此问题的示例 。tKI无知

但是,由于该网站是使用 Svelte 和 Elder.js 构建的,因此我对成功页面的实现略有不同:tKI无知

  <script>    const WORKER_URL = 'https://github-oauth-login.alex-zdanov.workers.dev';    const browser = process.env.componentType !== 'server';    $: if (browser) {      const code = new URL(location.href).searchParams.get('code');      const error = new URL(location.href).searchParams.get('error');      if (code) {        // remove ?code=... from URL        const path = location.pathname + location.search.replace(/code=w+/, '').replace(/?$/, '');        history.pushState({}, '', path);        login(code);      }      if (error) {        location.replace('/');      }    }    async function login(code) {      try {        const response = await fetch(WORKER_URL, {          method: 'POST',          mode: 'cors',          headers: {            'content-type': 'application/json',          },          body: JSON.stringify({ code }),        });        const result = await response.text();        if (result.error) {          alert(JSON.stringify(result, null, 2));        }      } catch (error) {        alert(error);      }    }  </script>

Elder.js 的问题之一是加载时 JS 无法在“页面”上运行。这是因为在构建期间或客户端浏览器上呈现页面时,我们无法检查页面。不过有一种方法可以解决这个问题,将所有代码放入一个组件文件中,然后在成功页面上导入它。Elder.js 可以对组件进行水合,并允许您访问允许您检查组件是在服务器上还是在客户端的浏览器上呈现的变量。所以在上面的代码中,我们检查 browser 变量何时设置为 true,然后从 URL 中提取 OAuth 代码并清理它,然后检查代码是否存在并将带有代码的请求发布到 CW为了订阅用户。tKI无知

结论

差不多就是这样。这相当简单,没有真正的捕获。当您没有后端时,CW 似乎是一种使用 API 机密运行 JS 的好方法。在供应商锁定方面,工人的 JS 应该足够通用,可以在任何无服务器环境中工作,只需进行一些小的调整。此外,如果您想自己托管它,在您自己的运行在 Node 上的 HTTP 服务器上实现代码将是微不足道的。Cloudflare 还提供了一种使用 miniflare在本地运行工作程序的方法,但我不建议这样做。您还不如在那时设置一个 API。tKI无知


tKI无知

原文:https://abyteofcoding.com/blog/oauth-with-cloudflare-workers-on-a-statically-generated-site/ tKI无知


tKI无知

本文为转载文章,版权归原作者所有,不代表本站立场和观点。

很赞哦! () 有话说 ()