如何使用 Cloudflare Workers 进行基本身份验证

*神户缘西(神户三宫)

大家好!
我是来自Beyond Inc.大阪办公室的拉面大王Hide。
这是我的第13篇帖子。

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

[AWS IAM] 仅允许在特定托管区域中查看的策略设置

 

 

概述

 

我想使用基本身份验证来限制访问……
因为我正在使用 Cloudflare,并且不想给我的源服务器增加压力,所以
我想在 Cloudflare 中实现基本身份验证……
嗯?但我该怎么做呢?

 

你有没有想过以上问题?
通常情况下,实现基本身份验证时,你会使用 Apache 或 Nginx。
我也会使用 Cloudflare 来减轻源服务器的负载,所以我在想是否也可以用 Cloudflare 来实现基本身份验证。结果发现,
使用 Cloudflare Workers 就能实现基本身份验证。
这非常方便,因为 Cloudflare 作为上一步,不会给源服务器带来任何负载!
步骤非常简单,让我们一起来试试吧!

 

 

先决知识

什么是 Cloudflare Workers?

Cloudflare是全球最大的CDN网络之一。世界各地的网络内容都使用Cloudflare的CDN服务来加速网站加载。Cloudflare
Workers是Cloudflare开发的无服务器服务。

您可以构建 Web 功能和应用程序,无需配置或维护基础设施,即可将其部署到 Cloudflare 遍布全球的 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
*服务和环境可在步骤⑦添加的代码屏幕中确认

 

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

 

⑩ 操作检查

・登录界面

 

登录后的内容屏幕

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

 

 

 

概括

您觉得怎么样?
使用 Cloudflare Workers,即使是免费套餐也能轻松实现基本身份验证!
这项服务还能防止因 Apache 或 Nginx 配置更改或写入错误导致的内容中断。
您还可以最大限度地利用 Cloudflare 的优势,而无需增加源服务器的负载。
如果您正在使用 Cloudflare 并希望实现基本身份验证,请务必参考本文!

如果您觉得这篇文章有帮助,请点赞!
3
加载中...
3 票,平均:1.00 / 13
4,196
X Facebook 哈特纳书签 口袋

写这篇文章的人

关于作者

隐藏@基础设施工程师

这一切都始于一次非常有趣的采访。
大阪系统解决方案部门的一名职业中期员工。我的
工作是构建和运营服务器和云!
我拥有 LPIC1、AWS SAA 和 OCI 架构师助理资格。

其实我很喜欢拉面,
已经调查过大阪100多家店了(。-∀-)我要努力成为Nibi Beyond

我也在Twitter,所以请关注我(´∇`)
点击右上角的Twitter标记! !