无密码验证:服务器 | Linux 中国

找不到分类 evilven 4个月前 (03-12) 51次浏览 已收录 0个评论 扫描二维码
无密码验证:服务器 | Linux 中国

无密码验证可以让你只输入一个 email 而无需输入密码即可登入系统。这是一种比传统的电子邮件/密码验证方式登入更安全的方法。
— Nicolás Parada


致谢
编译自 | https://nicolasparada.netlify.com/posts/passwordless-auth-server/ 
 作者 | Nicolás Parada
 译者 | qhwdw 🌟 🌟 🌟 🌟 🌟 共计翻译:117 篇 贡献时间:212 天

无密码验证可以让你只输入一个 email 而无需输入密码即可登入系统。这是一种比传统的电子邮件/密码验证方式登入更安全的方法。

下面我将为你展示,如何在 Go[1] 中实现一个 HTTP API 去提供这种服务。

流程

◈ 用户输入他的电子邮件地址。
◈ 服务器创建一个临时的一次性使用的代码(就像一个临时密码一样)关联到用户,然后给用户邮箱中发送一个“魔法链接”。
◈ 用户点击魔法链接。
◈ 服务器提取魔法链接中的代码,获取关联的用户,并且使用一个新的 JWT 重定向到客户端。
◈ 在每次有新请求时,客户端使用 JWT 去验证用户。

必需条件

◈ 数据库:我们为这个服务使用了一个叫 CockroachDB[2] 的 SQL 数据库。它非常像 postgres,但它是用 Go 写的。
◈ SMTP 服务器:我们将使用一个第三方的邮件服务器去发送邮件。开发的时我们使用 mailtrap[3]。Mailtrap 发送所有的邮件到它的收件箱,因此,你在测试时不需要创建多个假邮件帐户。

从 Go 的主页[4] 上安装它,然后使用 go version(1.10.1 atm)命令去检查它能否正常工作。

从 CockroachDB 的主页[5] 上下载它,展开它并添加到你的 PATH 变量中。使用 cockroach version(2.0 atm)命令检查它能否正常工作。

数据库模式

现在,我们在 GOPATH 目录下为这个项目创建一个目录,然后使用 cockroach start 启动一个新的 CockroachDB 节点:

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">cockroach start </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">--</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">insecure </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">--</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">host </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">127.0</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">0.1</span></code></p></li></ol>

它会输出一些内容,找到 SQL 地址行,它将显示像 postgresql://root@127.0.0.1:26257?sslmode=disable 这样的内容。稍后我们将使用它去连接到数据库。

使用如下的内容去创建一个 schema.sql 文件。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">DROP DATABASE IF EXISTS passwordless_demo CASCADE</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">;</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">CREATE DATABASE IF NOT EXISTS passwordless_demo</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">;</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">SET DATABASE </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> passwordless_demo</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">;</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">CREATE TABLE IF NOT EXISTS </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">users</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> UUID PRIMARY KEY DEFAULT gen_random_uuid</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    email STRING UNIQUE</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    username STRING UNIQUE</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">CREATE TABLE IF NOT EXISTS verification_codes </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> UUID PRIMARY KEY DEFAULT gen_random_uuid</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    user_id UUID NOT NULL REFERENCES </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">users</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ON DELETE CASCADE</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    created_at TIMESTAMPTZ NOT NULL DEFAULT now</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">INSERT INTO </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">users</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> username</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> VALUES</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">'john@passwordless.local'</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">'john_doe'</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这个脚本创建了一个名为 passwordless_demo 的数据库、两个名为 users 和 verification_codes 的表,以及为了稍后测试而插入的一些假用户。每个验证代码都与用户关联并保存创建时间,以用于去检查验证代码是否过期。

在另外的终端中使用 cockroach sql 命令去运行这个脚本:

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">cat</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> schema</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">sql </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">|</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> cockroach sql </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">--</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">insecure</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

环境配置

需要配置两个环境变量:SMTP_USERNAME 和 SMTP_PASSWORD,你可以从你的 mailtrap 帐户中获得它们。将在我们的程序中用到它们。

Go 依赖

我们需要下列的 Go 包:

◈ github.com/lib/pq[6]:它是 CockroachDB 使用的 postgres 驱动
◈ github.com/matryer/way[7]: 路由器
◈ github.com/dgrijalva/jwt-go[8]: JWT 实现
<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">go </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">get</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">-</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">u github</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">com</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">/</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">lib</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">/</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">pq</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">go </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">get</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">-</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">u github</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">com</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">/</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">matryer</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">/</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">way</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">go </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">get</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">-</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">u github</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">com</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">/</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">dgrijalva</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">/</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">-</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">go</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

代码

初始化函数

创建 main.go 并且通过 init 函数里的环境变量中取得一些配置来启动。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">struct</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    port        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">int</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    appURL      </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">URL</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    databaseURL string</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    jwtKey      </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">byte</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    smtpAddr    string</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    smtpAuth    smtp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Auth</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">init</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">port</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> _ </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> strconv</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Atoi</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">env</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"PORT"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"80"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">appURL</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> _ </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Parse</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">env</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"APP_URL"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"http://localhost:"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">strconv</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Itoa</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">port</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)+</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"/"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">databaseURL </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">env</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"DATABASE_URL"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"postgresql://root@127.0.0.1:26257/passwordless_demo?sslmode=disable"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwtKey </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">byte</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">env</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"JWT_KEY"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"super-duper-secret-key"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    smtpHost </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">env</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"SMTP_HOST"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"smtp.mailtrap.io"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">smtpAddr </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> net</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">JoinHostPort</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">smtpHost</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">env</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"SMTP_PORT"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"25"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    smtpUsername</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> os</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">LookupEnv</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"SMTP_USERNAME"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        log</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Fatalln</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not find SMTP_USERNAME on environment variables"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    smtpPassword</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> os</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">LookupEnv</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"SMTP_PASSWORD"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        log</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Fatalln</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not find SMTP_PASSWORD on environment variables"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">smtpAuth </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> smtp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">PlainAuth</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> smtpUsername</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> smtpPassword</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> smtpHost</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">env</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">key</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fallbackValue string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    v</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> os</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">LookupEnv</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">key</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fallbackValue</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> v</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>
◈ appURL 将去构建我们的 “魔法链接”。
◈ port 将要启动的 HTTP 服务器。
◈ databaseURL 是 CockroachDB 地址,我添加 /passwordless_demo 前面的数据库地址去表示数据库名字。
◈ jwtKey 用于签名 JWT。
◈ smtpAddr 是 SMTP_HOST + SMTP_PORT 的联合;我们将使用它去发送邮件。
◈ smtpUsername 和 smtpPassword 是两个必需的变量。
◈ smtpAuth 也是用于发送邮件。

env 函数允许我们去获得环境变量,不存在时返回一个回退值。

主函数

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">sql</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">DB</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func main</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err error</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> sql</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Open</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"postgres"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">databaseURL</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        log</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Fatalf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not open database connection: %vn"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    defer db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Close</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Ping</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">();</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        log</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Fatalf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not ping to database: %vn"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    router </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> way</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">NewRouter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    router</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandleFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"POST"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"/api/users"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jsonRequired</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">createUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    router</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandleFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"POST"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"/api/passwordless/start"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jsonRequired</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">passwordlessStart</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    router</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandleFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"GET"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"/api/passwordless/verify_redirect"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> passwordlessVerifyRedirect</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    router</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Handle</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"GET"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"/api/auth_user"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> authRequired</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">getAuthUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    addr </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Sprintf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">":%d"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">port</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    log</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Printf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"starting server at %s n"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">appURL</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    log</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Fatalf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not start server: %vn"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ListenAndServe</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">addr</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> router</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

首先,打开数据库连接。记得要加载驱动。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">import</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    _ </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"github.com/lib/pq"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

然后,我们创建路由器并定义一些端点。对于无密码流程来说,我们使用两个端点:/api/passwordless/start 发送魔法链接,和 /api/passwordless/verify_redirect 用 JWT 响应。

最后,我们启动服务器。

你可以创建空处理程序和中间件去测试服务器启动。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func createUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func passwordlessStart</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func passwordlessVerifyRedirect</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func getAuthUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotImplemented</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func jsonRequired</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> func</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func authRequired</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> func</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

接下来:

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">go build</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">./</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">passwordless</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">-</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">demo</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

我们在目录中有了一个 “passwordless-demo”,但是你的目录中可能与示例不一样,go build 将创建一个同名的可执行文件。如果你没有关闭前面的 cockroach 节点,并且你正确配置了 SMTP_USERNAME 和 SMTP_PASSWORD 变量,你将看到命令 starting server at http://localhost/ 没有错误输出。

请求 JSON 的中间件

端点需要从请求体中解码 JSON,因此要确保请求是 application/json 类型。因为它是一个通用的东西,我将它解耦到中间件。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func jsonRequired</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> func</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        ct </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Header</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Get</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Content-Type"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        isJSON </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">strings</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HasPrefix</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ct</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"application/json"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">isJSON </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"JSON body required"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnsupportedMediaType</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

实现很容易。首先它从请求头中获得内容的类型,然后检查它是否是以 “application/json” 开始,如果不是则以 415 Unsupported Media Type 提前返回。

响应 JSON 的函数

以 JSON 响应是非常通用的做法,因此我把它提取到函数中。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> payload </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">interface</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{},</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> code </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">int</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">switch</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> value </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> payload</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">type</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">case</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        payload </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"message"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> value</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">case</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">int</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        payload </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">int</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"value"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> value</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">case</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">bool</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        payload </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">bool</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"result"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> value</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    b</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> json</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Marshal</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">payload</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not marshal response payload: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Header</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">().</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Content-Type"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"application/json; charset=utf-8"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">WriteHeader</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">code</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Write</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">b</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

首先,对原始类型做一个类型判断,并将它们封装到一个 map。然后将它们编组到 JSON,设置响应内容类型和状态码,并写 JSON。如果 JSON 编组失败,则响应一个内部错误。

响应内部错误的函数

respondInternalError 是一个响应 500 Internal Server Error 的函数,但是也同时将错误输出到控制台。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    log</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Println</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusInternalServerError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusInternalServerError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

创建用户的处理程序

下面开始编写 createUser 处理程序,因为它非常容易并且是 REST 式的。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">type </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">User</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">struct</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    ID       string </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`json:"id"`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    string </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`json:"email"`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Username</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`json:"username"`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

User 类型和 users 表相似。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    rxEmail </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> regexp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MustCompile</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"^[^\s@]+@[^\s@]+\.[^\s@]+$"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    rxUsername </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> regexp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MustCompile</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"^[a-zA-Z][\w|-]{1,17}$"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这些正则表达式是分别用于去验证电子邮件和用户名的。这些都很简单,可以根据你的需要随意去适配。

现在,在 createUser 函数内部,我们将开始解码请求体。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">User</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> json</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">NewDecoder</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Decode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusBadRequest</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">defer r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Close</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

我们将使用请求体去创建一个 JSON 解码器来解码出一个用户指针。如果发生错误则返回一个 400 Bad Request。不要忘记关闭请求体读取器。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Email required"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">rxEmail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MatchString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid email"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Username</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"username"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Username required"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">rxUsername</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MatchString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Username</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"username"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid username"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> len</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">0</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnprocessableEntity</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这是我如何做验证;一个简单的 map 并检查如果 len(errs) != 0,则使用 422 Unprocessable Entity 去返回。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">QueryRowContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    INSERT INTO users (email, username) VALUES ($1, $2)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    RETURNING id</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Username</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Scan</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errPq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.(*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">pq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">&&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errPq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Code</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"unique_violation"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">strings</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Contains</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errPq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Email taken"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"username"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Username taken"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusForbidden</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not insert user: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这个 SQL 查询使用一个给定的 email 和用户名去插入一个新用户,并返回自动生成的 id,每个 $ 将被接下来传递给 QueryRowContext 的参数替换掉。

因为 users 表在 email 和 username 字段上有唯一性约束,因此我将检查 “unique_violation” 错误并返回 403 Forbidden 或者返回一个内部错误。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusCreated</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

最后使用创建的用户去响应。

无密码验证开始部分的处理程序

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">type </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">PasswordlessStartRequest</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">struct</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">       string </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`json:"email"`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RedirectURI</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`json:"redirectUri"`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这个结构体含有 passwordlessStart 的请求体:希望去登入的用户 email、来自客户端的重定向 URI(这个应用中将使用我们的 API)如:https://frontend.app/callback

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> magicLinkTmpl </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">template</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Must</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">template</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ParseFiles</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"templates/magic-link.html"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

我们将使用 golang 模板引擎去构建邮件,因此需要你在 templates 目录中,用如下的内容创建一个 magic-link.html 文件:

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="dec" style="word-wrap: break-word;color: rgb(51, 135, 204);"><!DOCTYPE html></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><html</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">lang</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"en"</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);">></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><head></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><meta</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">charset</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"utf-8"</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);">></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><meta</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"viewport"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">content</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"width=device-width, initial-scale=1.0"</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);">></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><title></span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">Magic Link</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"></title></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"></head></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><body></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    Click </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><a</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">href</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"{{ .MagicLink }}"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">target</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"_blank"</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);">></span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">here</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"></a></span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> to login.</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><br></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><em></span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">This link expires in 15 minutes and can only be used once.</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"></em></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"></body></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"></html></span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这个模板是给用户发送魔法链接邮件用的。你可以根据你的需要去随意调整它。

现在, 进入 passwordlessStart 函数内部:

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">PasswordlessStartRequest</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> json</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">NewDecoder</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Decode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusBadRequest</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">defer r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Close</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

首先,我们像前面一样解码请求体。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Email required"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">rxEmail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MatchString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid email"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RedirectURI</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirectUri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Redirect URI required"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> u</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Parse</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RedirectURI</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">||</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">u</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">IsAbs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirectUri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid redirect URI"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> len</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">0</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnprocessableEntity</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

我们使用 golang 的 URL 解析器去验证重定向 URI,检查那个 URI 是否为绝对地址。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode string</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">QueryRowContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    INSERT INTO verification_codes (user_id) VALUES</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">        ((SELECT id FROM users WHERE email = $1))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    RETURNING id</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Scan</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errPq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.(*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">pq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">&&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errPq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Code</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"not_null_violation"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"No user found with that email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotFound</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not insert verification code: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这个 SQL 查询将插入一个验证代码,这个代码通过给定的 email 关联到用户,并且返回一个自动生成的 id。因为有可能会出现用户不存在的情况,那样的话子查询可能解析为 NULL,这将导致在 user_id 字段上因违反 NOT NULL 约束而导致失败,因此需要对这种情况进行检查,如果用户不存在,则返回 404 Not Found 或者一个内部错误。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Values</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RedirectURI</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">magicLink </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">appURL</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">magicLink</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Path</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"/api/passwordless/verify_redirect"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">magicLink</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RawQuery</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Encode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

现在,构建魔法链接并设置查询字符串中的 verification_code 和 redirect_uri 的值。如:http://localhost/api/passwordless/verify_redirect?verification_code=some_code&redirect_uri=https://frontend.app/callback

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body bytes</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Buffer</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">data </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"MagicLink"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> magicLink</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> magicLinkTmpl</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Execute</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> data</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not execute magic link template: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

我们将得到的魔法链接模板的内容保存到缓冲区中。如果发生错误则返回一个内部错误。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> mail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> sendMail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Magic Link"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">());</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not mail magic link: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

现在来写给用户发邮件的 sendMail 函数。如果发生错误则返回一个内部错误。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">WriteHeader</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNoContent</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

最后,设置响应状态码为 204 No Content。对于成功的状态码,客户端不需要很多数据。

发送邮件函数

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func sendMail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to mail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> error </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">from</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> mail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Passwordless Demo"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"noreply@"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">appURL</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Host</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    headers </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"From"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">         </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">from</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"To"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">           to</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Subject"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">      subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Content-Type"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`text/html; charset="utf-8"`</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">for</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> k</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> v </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> range headers </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Sprintf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"%s: %srn"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> k</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> v</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"rn"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> smtp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SendMail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">smtpAddr</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">smtpAuth</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">from</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">},</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">byte</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">msg</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这个函数创建一个基本的 HTML 邮件结构体并使用 SMTP 服务器去发送它。邮件的内容你可以随意定制,我喜欢使用比较简单的内容。

无密码验证重定向的处理程序

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> rxUUID </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> regexp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MustCompile</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

首先,这个正则表达式去验证一个 UUID(即验证代码)。

现在进入 passwordlessVerifyRedirect 函数内部:

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">URL</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Query</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">verificationCode </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Get</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">redirectURI </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Get</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

/api/passwordless/verify_redirect 是一个 GET 端点,以便于我们从查询字符串中读取数据。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Verification code required"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">rxUUID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MatchString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid verification code"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> callback </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">URL</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err error</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> redirectURI </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Redirect URI required"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Parse</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">redirectURI</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">||</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">IsAbs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid redirect URI"</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> len</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">0</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnprocessableEntity</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

类似的验证,我们保存解析后的重定向 URI 到一个 callback 变量中。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> userID string</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">QueryRowContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    DELETE FROM verification_codes</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    WHERE id = $1</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">        AND created_at >= now() - INTERVAL '15m'</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    RETURNING user_id</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Scan</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">userID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> sql</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ErrNoRows</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Link expired or already used"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusBadRequest</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not delete verification code: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这个 SQL 查询通过给定的 id 去删除相应的验证代码,并且确保它创建之后时间不超过 15 分钟,它也返回关联的 user_id。如果没有检索到内容,意味着代码不存在或者已过期,我们返回一个响应信息,否则就返回一个内部错误。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">expiresAt </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">time</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Now</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">().</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Add</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">time</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Hour</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">24</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">60</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">tokenString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">NewWithClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SigningMethodHS256</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StandardClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">   userID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ExpiresAt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> expiresAt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Unix</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SignedString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwtKey</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not create JWT: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

这些是如何去创建 JWT。我们为 JWT 设置一个 60 天的过期值,你也可以设置更短的时间(大约 2 周),并添加一个新端点去刷新令牌,但是不要搞的过于复杂。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">expiresAtB</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> expiresAt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MarshalText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not marshal expiration date: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">f </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Values</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">f</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"jwt"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> tokenString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">f</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"expires_at"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">expiresAtB</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Fragment</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> f</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Encode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

我们去规划重定向;你可使用查询字符串去添加 JWT,但是更常见的是使用一个哈希片段。如:https://frontend.app/callback#jwt=token_here&expires_at=some_date.

过期日期可以从 JWT 中提取出来,但是这样做的话,就需要在客户端上实现一个 JWT 库来解码它,因此为了简化,我将它加到这里。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Redirect</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusFound</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

最后我们使用一个 302 Found 重定向。


无密码的流程已经完成。现在需要去写 getAuthUser 端点的代码了,它用于获取当前验证用户的信息。你应该还记得,这个端点使用了 guard 中间件。

使用 Auth 中间件

在编写 guard 中间件之前,我将编写一个不需要验证的分支。目的是,如果没有传递 JWT,它将不去验证用户。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">type </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ContextKey</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">struct</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> keyAuthUserID </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ContextKey</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"auth_user_id"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func withAuth</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> func</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        a </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Header</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Get</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Authorization"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        hasToken </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">strings</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HasPrefix</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">a</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Bearer "</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">hasToken </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        tokenString </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> a</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">7</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:]</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        p </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Parser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ValidMethods</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SigningMethodHS256</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> p</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ParseWithClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            tokenString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StandardClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{},</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            func </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">interface</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{},</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwtKey</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">},</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        claims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Claims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.(*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StandardClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">||</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Valid</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        ctx </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        ctx </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">WithValue</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> keyAuthUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> claims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">WithContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
</ol>

JWT 将在每次请求时以 Bearer <token_here> 格式包含在 Authorization 头中。因此,如果没有提供令牌,我们将直接通过,进入接下来的中间件。

我们创建一个解析器来解析令牌。如果解析失败则返回 401 Unauthorized

然后我们从 JWT 中提取出要求的内容,并添加 Subject(就是用户 ID)到需要的地方。

Guard 中间件

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func guard</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> withAuth</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        _</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">().</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Value</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">keyAuthUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">})</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
</ol>

现在,guard 将使用 withAuth 并从请求内容中提取出验证用户的 ID。如果提取失败,它将返回 401 Unauthorized,提取成功则继续下一步。

获取 Auth 用户

在 getAuthUser 处理程序内部:

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">authUserID </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Value</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">keyAuthUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fetchUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> authUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> sql</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ErrNoRows</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusTeapot</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusTeapot</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not query auth user: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusOK</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

首先,我们从请求内容中提取验证用户的 ID,我们使用这个 ID 去获取用户。如果没有获取到内容,则发送一个 418 I'm a teapot,或者一个内部错误。最后,我们将用这个用户去响应。

获取 User 函数

下面你看到的是 fetchUser 函数。

<ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;">
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func fetchUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">User</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    user </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">User</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">QueryRowContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">        SELECT email, username FROM users WHERE id = $1</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    `</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Scan</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Username</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li>
<li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"></code></p></li>
</ol>

我将它解耦是因为通过 ID 来获取用户是个常做的事。


以上就是全部的代码。你可以自己去构建它和测试它。这里[9] 还有一个 demo 你可以试用一下。

如果你在 mailtrap 上点击之后出现有关 脚本运行被拦截,因为文档的框架是沙箱化的,并且没有设置 'allow-scripts' 权限 的问题,你可以尝试右键点击 “在新标签中打开链接“。这样做是安全的,因为邮件内容是 沙箱化的[10]。我在 localhost 上有时也会出现这个问题,但是我认为你一旦以 https:// 方式部署到服务器上应该不会出现这个问题了。

如果有任何问题,请在我的 GitHub repo[11] 留言或者提交 PRs

以后,我为这个 API 写了一个客户端作为这篇文章的第二部分[12]


via: https://nicolasparada.netlify.com/posts/passwordless-auth-server/

作者:Nicolás Parada[14] 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出


Hacking For Fun , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:无密码验证:服务器 | Linux 中国
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址