伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

构建一个带身份验证的 Deno 应用

来源:本站原创 浏览:49次 时间:2023-07-06
构建一个带身份验证的 Deno 应用

疯狂的技术宅 前端先锋

Node.js 的创建者 Ryan Dahl 创建了一个用于设计 Web 应用程序的新框架。他回过头来,利用在最初编写 Node 时还不可用的新技术,纠正了事后发现的一些错误。这就是 Deno[1](发音为 DEH-no),一个用 TypeScript 编写的 “类似 Node 的” Web 应用的框架。在本文中,我将引导你创建一个带有身份验证的基本 Web 应用。


要点
创建你的 Deno 应用
用 Deno 构建真实的 Web 应用
为你的 Deno 应用添加功能
用 Okta 添加身份验证
运行 Deno 程序

你几乎可以在 Deno 网站上找到所需的所有信息,以及有关当前可用于 Deno 的所有第三方库的信息。当前框架最大的缺点应该是:它只是在 2020 年 5 月 13 日发行了1.0版,因此即使有很多基本库,也没有 Node 的库那么多。不过对于那些精通 Node 的人,向 Deno 过渡应该很容易。

你可以在 https://deno.land/#installation 中找到安装说明。

创建你的 Deno 应用

我找不到任何基本的脚手架库,所以只能从一个空文件夹开始。在程序的根文件夹中,创建一个名为 index.ts 的文件,这将作为你 Deno 程序的起点。我们将会使用 Opine[2],它是 Deno 的 Express 克隆版本,可简化构建和路由。

与 Deno 不同的是,没有用于引入第三方库的包管理器。你可以通过使用库的完整 URL 来完成此操作。在 index.ts 文件顶部执行此操作,然后设置一个基本的 Web 应用程序。

import { opine } from 'https://deno.land/x/opine@0.12.0/mod.ts';const app = opine();app.get('/', (req, res) => {  res.send('Deno Sample');});app.listen(3000);console.log('running on port 3000');

然后,在终端下切换到程序文件夹中,并输入以下内容来运行这个非常基本的程序:

deno run -A index.ts

-A 是用于开发目的的快捷选项。在默认情况下,Deno 完全处于锁定状态,所以需要把参数传递给 run 命令以允许访问,例如 --allow-net 允许联网, --allow-read 允许程序从文件系统读取。这里的 -A 允许所有内容,从而有效地禁用了所有安全性。当你运行这个程序然后转到 http://localhost:3000 时,空白页上将会出现 「Deno Sample」 字样。

用 Deno 构建真实的 Web 应用

虽然这是一个良好的开端,但并没有太大用处。你还需要添加一些“真实”的功能,这些功能比“真实世界”要多一些,接下来修改 index.ts 文件,使其内容为:

import { opine, serveStatic } from 'https://deno.land/x/opine@0.12.0/mod.ts';import { renderFileToString } from 'https://deno.land/x/dejs@0.7.0/mod.ts';import { join, dirname } from 'https://deno.land/x/opine@main/deps.ts';import { ensureAuthenticated } from './middleware/authmiddleware.ts';import users from './controllers/usercontroller.ts';import auth from './controllers/authcontroller.ts';const app = opine();const __dirname = dirname(import.meta.url);app.engine('.html', renderFileToString);app.use(serveStatic(join(__dirname, 'public')));app.set('view engine', 'html');app.get('/', (req, res) => {  res.render('index', { title: 'Deno Sample' });});app.use('/users', ensureAuthenticated, users);app.use('/auth', auth)app.listen(3000);console.log('running on port 3000');

你会注意到很多的 import 语句,这些语句引入了一些第三方库。在这里,我用的是 dejs[3],这是 Deno 的 EJS 端口。我还引入了 Opine 库中的一些用于处理目录名称的类。我在后面将会介绍本地导入的这三个文件。现在你只需要知道导入了它们。

opine() 实例化下面的代码行创建对本地目录的引用。下面的三行代码将视图引擎设置为 DEJS,用来处理类似 HTML 的文件,这很像 EJS 对 Node 的处理方式。下一部分已稍作更改以渲染这些 HTML 模板文件,并且最后两行代码引入了一些外部路由。需要注意的一件事是 /users 路由具有 ensureAuthenticated() 中间件功能。这将迫使用户先登录,然后才能访问该页面。

为你的 Deno 应用添加功能

接下来创建一些在上面代码所缺失的部分。从路由开始。在程序的根目录中创建一个名为 controllers 的文件夹。然后在该文件夹内添加一个 usercontroller.ts 文件,内容如下:

import { Router } from 'https://deno.land/x/opine@0.12.0/mod.ts';const users = new Router();// users routesusers.get('/me', (req, res) => {  res.render('users/me', { title: 'My Profile', user: res.app.locals.user });});export default users;

这是一个简单的路由文件。它从 Opine 获取路由,并创建一个新实例来挂起路由。然后有代码为 /me 添加路由以在 users/me 中渲染 HTML 视图。render() 调用还将标题和登录用户传递到页面。该页面将受到保护,以便始终有用户可以访问。

接下来,创建一些点击路由时能够显示的视图。在根文件夹中,添加一个 views 文件夹。在其中创建一个 shared 文件夹和一个 users 文件夹。在 shared 文件夹中,创建一个 header.html 和 footer.html 文件。在 users 文件夹中添加 me.html 文件。最后,在 views 文件夹本身中创建一个 index.html 文件。

这些是非常简单的方法,但是它演示了如何创建可被其他视图重用的视图。在 shared/header.html 文件中添加以下内容:

<!DOCTYPE html><html lang="en"><head>  <meta charset="utf-8">  <meta name="viewport" content="width=device-width,initial-scale=1">  <title><%= title %></title></head><body>  

这将输出 HTML 页面的顶部,并将标题注入页面。接下来,将以下内容添加到 shared/footer.html 文件中:

</body></html>

现在你可以在 index.html 文件中使用这些局部变量:

<%- await include('views/shared/header.html', { title }); %><a href="/users/me">My Profile</a><%- await include('views/shared/footer.html'); %>

这包括页脚和页眉部分的内容,并向个人资料页面添加了链接。users/me.html 文件的内容是:

<%- await include('views/shared/header.html', { title }); %><h1>My Profile</h1><ul><% for(var p in user){ %>  <li><strong><%= p %>: </strong><%= user[p] %></li><% } %></ul><%- await include('views/shared/footer.html'); %>

同样,此页面包含页眉和页脚,并循环遍历 user 对象的属性。当然这不是一个漂亮的个人资料页面,但是它能够使你知道身份验证步骤是否全部有效。

用 Okta 添加身份验证

如果你还没有Okta帐户,可以在此处获得免费的开发人员帐户[4]。登录 Okta 后进入仪表板。你需要创建一个 Okta 应用,以利用 Okta 作为项目的身份提供者。

单击菜单中的 「Applications」,然后单击 「Add Application」。这将带你进入应用程序向导。选择 「Web」 作为你的平台,然后单击 「Next」。下一页是 「Application Settings」 页面。为你的应用程序命名(我命名为 DenoExample)。将所有 URL 更改为使用端口 3000 而不是 8080,然后将 「Login Redirect URIs」 更改为 http://localhost:3000/auth/callback。最后,单击 「Done」 在 Okta 中创建应用程序。

进入新创建的应用程序页面后,确保你位于 「General Settings」 选项卡上并滚动到底部,直到看到 「Client Credentials」 部分。我们先暂时使用这些值,所以不要关闭这个窗口。

回到你的应用程序中,在程序的根目录中创建一个名为 .env 的新文件。该文件的内容将是:

issuer=https://{yourOktaOrgUrl}/oauth2/defaultclientId={yourClientID}clientSecret={yourClientSecret}redirectUrl=http://localhost:3000/auth/callbackstate=SuPeR-lOnG-sEcReT

从 Okta 应用程序的 「Client Credentials」 部分复制客户端 ID 和客户端密钥。然后返回到信息中心,从菜单下方的右侧复制你的 Okta org URL。

现在你可以开始用 Okta 进行身份验证了。不幸的是你必须手动创建它。不过这是一个很棒的练习,可以帮助你了解 OAuth 和 OIDC 的工作方式。在程序的根文件夹中,创建一个名为 middleware 的新文件夹,并添加一个名为 authmiddleware.ts 的文件。然后添加以下内容:

import { config } from 'https://deno.land/x/dotenv/mod.ts';export const ensureAuthenticated = async (req:any, res:any, next:any) => {  const user = req.app.locals.user;  if(!user){    const reqUrl = req.originalUrl;    const {issuer, clientId, redirectUrl, state} = config();    const authUrl = `${issuer}/v1/authorize?client_id=${clientId}&response_type=code&scope=openid%20email%20profile&redirect_uri=${encodeURIComponent(redirectUrl)}&state=${state}:${reqUrl}`;    res.location(authUrl).sendStatus(302);  }  next();}

首先,导入一个用于读取 .env 文件的库 dotenv[5]。然后实现 ensureAuthenticated() 中间件,该中间件将启动身份验证过程的第一步。它首先检用户是否登录。如果已登录,则它只调用 next(),因为无事可做。

如果没有当前登录的用户,它将从 .env 文件构建一个由 Issuer,clientId,redirectUrl 和 state 属性组成的 URL。它调用发行者 URL 的 /v1/authorize 端点。然后重定向到该 URL。这是 Okta 托管的登录页面。有点像当你重定向到 Google 并用其作为身份提供者登录的机制。登录完成后将要调用的 URL 是 .env 文件中的 URL http://localhost:3000/auth/callback 。我还标记了用户重定向到 state 查询参数时要使用的原始 URL。一旦他们登录,这将会很容易把他们直接引导回去。

接下来,你将需要实现 auth/callback 路由来处理登录页面的结果,并交换将从 Okta 收到的授权代码。在 controllers 文件夹中创建一个名为 authcontroller.ts 的文件,其内容如下:

import { Router } from 'https://deno.land/x/opine@0.12.0/mod.ts';import { config } from "https://deno.land/x/dotenv/mod.ts";const auth = new Router();// users routesauth.get('/callback', async (req, res) => { const { issuer, clientId, clientSecret, redirectUrl, state } = config(); if (req.query.state.split(':')[0] !== state) {   res.send('State code does not match.').sendStatus(400); } const tokenUrl: string = `${issuer}/v1/token`; const code: string = req.query.code; const headers = new Headers(); headers.append('Accept', 'application/json'); headers.append('Authorization', `Basic ${btoa(clientId + ':' + clientSecret)}`); headers.append('Content-Type', 'application/x-www-form-urlencoded'); const response = await fetch(tokenUrl, {   method: 'POST',   headers: headers,   body: `grant_type=authorization_code&redirect_uri=${encodeURIComponent(redirectUrl)}&code=${code}` }); const data = await response.json(); if (response.status !== 200) {   res.send(data); } const user = parseJwt(data.id_token); req.app.locals.user = user; req.app.locals.isAuthenticated = true; res.location(req.query.state.split(':')_[_1] || '/').sendStatus(302);});function parseJwt (token:string) {  const base64Url = token.split('.')_[_1];  const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');  const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {      return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);  }).join(''));  return JSON.parse(jsonPayload);};export default auth;

实际上,这里发生的事比你想象的要少得多。首先从 Opine 引入 Router,然后再次读取 .env 文件。接着他们像在 usercontroller.ts 文件中一样实例化路由器。接下来是解构 config 对象,能够更易于使用它的值。接下来,我检查了状态查询参数以确保其匹配。这有助于确保 Okta 是发送授权码的人。然后用 req.query.code 从查询字符串中提取授权码。

接下来是对 token 端点的调用。你将在 POST 请求中将授权码发送给 Okta,以交换 ID Token。因此,这里我为请求构建了一些标头。最重要的是 Authorization 标头,其值为 Basic {yourClientId}:{yourClientSecret},客户端 ID 和密码是 base64 编码的。然后,使用这些标头和带有 authorization_code 的 grant_type(与以前相同的重定向 URL)的主体,以及带有我刚从 Okta 收到的授权代码的 Token 端点,对 Token 端点进行 POST 调用。

fetch() 调用返回一个用 then() 函数解析的 promise。我得到 response 对象的JSON值,为了确保调用成功,用下面的 parseJwt() 函数解析 id_token 值并将其粘贴到名为 user 的局部变量中。最后在重定向到身份验证之前,将用户发送到他们最初请求的 URL。

运行 Deno 程序

现在用以下命令从终端再次运行该程序:

deno run -A index.ts


一旦运行,你将能够单击主页上的配置文件链接,并将其重定向到 Okta 的托管登录页面。登录后,将会直接回到个人资料页面,你会看到 ID Token 的属性显示在列表中。


作者:Lee Brandt
翻译:疯狂的技术宅
原文:https://scotch.io/tutorials/build-your-first-deno-app-with-authentication


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net