如何将基本身份验证与 Cloudflare Workers 结合使用

*神户缘西(神户三宫)

大家好!
我是来自Beyond Co., Ltd.大阪办事处的拉面之王Hide。
这是我的第13篇帖子。

上次我写了一篇关于如何在 AWS IAM 中设置策略的文章,这些策略只允许访问特定的托管区域!
设置过程相对简单,但如果设置错误,可能无法创建策略,或者可能会显示不应该显示的内容。
我已经用通俗易懂的方式解释了设置方法,如果您感兴趣,请查看一下。

[AWS IAM] 仅允许访问特定托管区域的策略设置

 

 

概述

 

我想使用基本身份验证来限制访问……
因为我使用的是 Cloudflare,而且我不想给源服务器增加负载,所以
我想在 Cloudflare 上实现基本身份验证……
但我该怎么做呢?

 

你有没有考虑过以上方案?
通常情况下,实现基本身份验证时,你会使用 Apache 或 Nginx 之类的服务。
我也在想是否可以使用 Cloudflare 来减轻源服务器的负载,结果发现可以
使用 Cloudflare Workers 来实现基本身份验证!
由于 Cloudflare 不会给源服务器增加任何负载,所以非常方便!
操作步骤很简单,让我们开始吧!

 

 

先决知识

什么是 Cloudflare Workers?

Cloudflare是全球最大的内容分发网络(CDN)之一。全球网络内容提供商都使用Cloudflare的CDN服务来优化网站速度。Cloudflare
Workers是Cloudflare开发的无服务器服务。

Cloudflare 让您无需配置或维护基础设施即可构建 Web 功能和应用程序,并可将其部署到全球超过 275 个数据中心。您
可以使用 JavaScript 和 TypeScript 等语言进行实现。Cloudflare
是一项极其便捷的服务,因为您可以将 SSL、WAF 和 CDN 与应用程序构建功能结合使用。

 

 

什么是基本身份验证?

此功能允许您使用 Apache 或 Nginx 等中间件来实现访问限制。
身份验证可以通过用户名和密码完成,因此适用于您希望仅允许特定用户访问的场景。

我们的工程师编写了一份关于如何使用 Nginx 实现基本身份验证的指南,
如果您感兴趣,请查看一下!

我尝试使用 Nginx 进行基本身份验证。

 

 

 

 

设置程序

*这假设 Cloudflare 的初始设置和记录注册已经完成。

① 点击首页 > 员工 > 概览

 

 

②输入任意子域名,然后点击【设置】

 

 

③选择定价方案

*这是一个演示版本,所以我们选择了“免费”,但请选择
Cloudflare Workers 定价方案

 

 

 

④点击【创建服务】

 

 

 

⑤输入服务名称,然后单击【创建服务】。

 

 

 

⑥点击【快速编辑】

 

 

 

 

⑦粘贴基本身份验证代码,然后单击[保存并部署]。

*请复制并粘贴基本身份验证代码。
* 编辑时,基本身份验证代码示例。请参考
* 您可以使用以下常量更改用户名和密码。

const BASIC_USER = ''; const BASIC_PASS = '';

・基本身份验证码

/** * 展示如何使用 HTTP 基本身份验证模式限制访问。 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication * @see https://tools.ietf.org/html/rfc7617 * * 包含冒号 (":") 字符的用户 ID 无效,因为 * 用户密码字符串中的第一个冒号用于分隔用户名和密码。 */ const BASIC_USER = ''; const BASIC_PASS = ''; /** * 接收 HTTP 请求并返回响应。 * @param {Request} 请求 * @returns {Promise}<Response> } */ async function handleRequest(request) { const { protocol, pathname } = new URL(request.url); // 对于基本身份验证,为了安全起见,交换必须通过 HTTPS (TLS) 连接进行。 if ('https:' !== protocol || 'https' !== request.headers.get('x-forwarded-proto')) { throw new BadRequestException('请通过 HTTPS 连接'); } // 身份验证通过后,会发送“Authorization”标头。 if (request.headers.has('Authorization')) { // 授权失败时抛出异常。 const { user, pass } = basicAuthentication(request); verifyCredentials(user, pass); return fetch(request) } // 未通过身份验证。 return new Response('登录需要用户名和密码', { status: 401, headers: { // 提示用户输入凭据。'WWW-Authenticate': 'Basic realm="my scope", charset="UTF-8"', }, }); } /** * 验证失败时抛出异常。 * @param {string} user * @param {string} pass * @throws {UnauthorizedException} */ function verifyCredentials(user, pass) { if (BASIC_USER !== user) { throw new UnauthorizedException('用户名或密码错误'); } if (BASIC_PASS !== pass) { throw new UnauthorizedException('用户名或密码错误'); } } /** * 解析 HTTP 基本身份验证值。 * @param {Request} 请求 * @throws {BadRequestException} * @returns {{ user: string, pass: string }} */ function basicAuthentication(request) { const Authorization = request.headers.get('Authorization'); const [scheme, encoded] = Authorization.split(' '); // Authorization 标头必须以 Basic 开头,后跟一个空格。 if (!encoded || scheme !== 'Basic') { new BadRequestException('错误的身份验证标头'); } // 解码 base64 值并执行 Unicode 规范化。 // @see https://datatracker.ietf.org/doc/html/rfc7613#section-3.3.2 (以及 #section-4.2.2) // @see https://dev.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/normalize const buffer = Uint8Array.from(atob(encoded), character => character.charCodeAt(0)); const decoded = new TextDecoder().decode(buffer).normalize(); // 用户名和密码以第一个冒号分隔。 //=> 例如:"username:password" const index = decoded.indexOf(':'); // 用户名和密码以第一个冒号分隔,且不得包含控制字符。 // @see https://tools.ietf.org/html/rfc5234#appendix-B.1 (=> "CTL = %x00-1F / %x7F") if (index === -1 || /[\0-\x1F\x7F]/.test(decoded)) { throw new BadRequestException('身份验证值无效。'); } return { user: decoded.substring(0, index), pass: decoded.substring(index + 1), }; } function UnauthorizedException(reason) { this.status = 401; this.statusText = '未授权'; this.reason = reason; } function BadRequestException(reason) { this.status = 400; this.statusText = '错误请求'; this.reason = reason; addEventListener('fetch', event => { event.respondWith( handleRequest(event.request).catch(err => { const message = err.reason || err.stack || 'Unknown Error'; return new Response(message, { status: err.status || 500, statusText: err.statusText || null, headers: { 'Content-Type': 'text/plain;charset=UTF-8', // 默认禁用缓存。 'Cache-Control': 'no-store', // 返回 HTTP HEAD 请求的“Content-Length”标头。 'Content-Length': message.length, }, }); }) ); });

 

 

*将出现以下弹出窗口,请点击[保存并部署]。

 

 

* 如果你想检查操作结果,可以进行预览。

 

 

 

8. 首页 > 已验证域 > 工作路由 > 点击 [添加路由]

 

 

 

9. 输入以下信息并点击【保存】。

根目录:example-test.com/*
*指定要为其设置基本身份验证的域名(FQDN)。
*也可以指定通配符。
服务:basic-test
环境:production
*服务和环境可以在步骤 7 添加的代码屏幕中确认。

 

保存后,它将显示在列表中。

 

⑩ 操作检查

・登录界面

 

登录后的内容屏幕

*基本身份验证对指定域(FQDN)以外的域无效。

 

 

 

概括

那么,您觉得怎么样?
使用 Cloudflare Workers,即使是免费套餐也能轻松实现基本身份验证!
这还有助于防止因 Apache/Nginx 配置更改和代码错误导致的内容中断。
此外,它还能让您在不增加源服务器负载的情况下,最大限度地利用 Cloudflare 的优势。
如果您正在使用 Cloudflare 并希望实现基本身份验证,请参考这里!

如果您觉得这篇文章对您有帮助,请点个“赞”!
3
加载中...
3票,平均分:1.00/13
4,637
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

隐藏@基础设施工程师

这要感谢一次非常有趣的面试。
我是在职业生涯中期加入公司大阪系统解决方案部门的,
我的工作涉及服务器和云服务的构建和运维!
我还持有LPIC1、AWS SAA和OCI架构师助理认证。

其实我超爱拉面,
已经探访过大阪100多家拉面店了(。-∀-)我正在努力成为Nihi Beyond的拉面之王
ビヨンドのラーメン王を目指し奮闘中!!

我也有推特账号,请关注我哦!(´∇`)
点击右上角的推特图标即可!