双因素认证对用户来说似乎是一个非常平庸的过程。许多人早已习惯了这样一个事实:在使用许多应用程序时,仅仅输入熟悉的登录和密码组合是不够的。为了增加安全性和防止未经授权的访问,引入了一个额外的验证因素。在大多数情况下,它是一个独特的代码,可以通过电子邮件或短信收到。
在本教程中,我们将学习如何在AppMaster 中实现双因素认证。作为一个例子,将使用发送代码的邮件。我们将分析需要连接哪些模块,进行哪些设置,创建哪些业务流程,以及如何在实践中检查完成的结果。
首先,让我们看一下总体计划。在我们的业务流程中需要实现哪些步骤?
- 登录验证(确保用户确实已经注册)。
- 检查密码是否正确。
- 通过邮件或短信发送一个确认码。
- 检查代码的相关性。
- 检查代码的正确性。
- С完成认证。
准备阶段
甚至在你开始设计双因素认证之前,在用户注册阶段,你就需要确定。
- 用户数据必须包含一个电子邮件。它将被用来发送验证码。电子邮件经常被用作登录,我们将看一下这样一个例子。
- 登录名是唯一的。系统中不能存在两个具有相同登录名的不同用户。
为了方便解决这些(和许多其他)任务,该 Auth模块被默认安装在每个AppMaster 项目中。它包含必要的数据库模型、业务流程块和使用它们的端点。
登录验证
登录、密码和验证码被用作业务流程的输入参数。但是在第一阶段,我们只需要一个登录名。这将有助于确定这个用户的存在。他已经被注册了,有关的信息被储存在数据库中。
要做到这一点,该 DB: Search User块在数据库中搜索一个具有给定登录名的用户。请确保将 SearchExact = True参数来搜索一个完全匹配的用户。
收到的数据被传递到 Array Element块,索引为0(计数从0开始,找到的唯一值总是对应于数组中的索引0)。
该 Is Null块检查是否真的找到了该用户。根据结果(True/False),该块将中断业务流程。 If-Else块会以错误信息打断业务流程(Raise Error块)或者进一步引导它。
密码检查
在这个阶段,你需要确保用户密码的输入是正确的。
在这里,我们必须明白,密码并没有明确地存储在数据库中。该 Bcrypt函数对它们进行了散列,而只有产生的散列值被存储在数据库中。因此,即使我们假设会发生数据泄漏,攻击者仍然无法找到用户密码;它们被安全地加密了。
由于这个原因,你不能简单地从数据库中获取密码并与输入的密码进行比较。你需要获得密码的哈希值,并使用它进行比较。为了解决这个问题,使用 Auth: Probe Password块被使用。作为输入参数,它接收用户输入的密码(password)和存储在数据库中的密码哈希值(hashed_password),并将其转换为String 数据类型(the To String块)。
根据结果,如上一步,使用 If-Else块,我们要么显示一个错误信息(Raise Error,Message = Password is wrong),或者引导进程进入下一个阶段。
用户模型扩展
下一步,你需要在用户模型中做一个小的改动,增加需要确认的密码信息。
一般来说,User 模型最初包含可用于这项任务的字段 -Confirmed, Confirmation code, Confirmation code expires at 。但是在这个例子中,我们将假设这些字段只用于注册和初始账户验证。
为了使过程更加清晰,让我们创建一个单独的twofa (two-factor authentication)模型,将User 模型与之关联(1对1关系,has one ),并添加一个字段--code (String 类型)。
准备发送电子邮件
为了发送带有确认码的电子邮件,应该进行初步准备。其中一个最方便的选择是使用 Custom SMTP模块,你需要安装和配置它。
当使用Gmail ,大多数设置已经默认设置,你需要添加你的用户名和密码。当使用其他邮件服务器时,如果你参考他们的文档以获得必要的数据,将会有所帮助。
在这种情况下,你可能需要稍微改变邮件服务器的安全设置。例如,Gmail 可能会默认阻止使用第三方应用程序的连接,你需要在设置中删除这一限制。
发送验证码
我们检查了登录和密码,完成了所有必要的准备工作,所以现在你可以着手发送带有确认码的信件。
该 Custom SMTP: Send Email块使用一个地址阵列作为目的地。因此,即使你只需要向一个地址发送信件,它也应该被添加到阵列中。为此,该 Append Array区块被使用。
下一步是生成一个验证码。该 Random string块适用于此。我们将发送一个由6个随机数组成的代码,并进行适当的设置。Length = 6, With 0-9 = True,所有其他参数=False 。
接下来,你需要创建信件的文本。要做到这一点,使用 Concat Strings块在生成的代码中添加说明性文本(First = Verification code: ),将结果转换为Text 数据类型(To Text块),并将结果连接到 body参数的电子邮件发送块。
对于最后的发送,只需要指定信件的主题(subject)和发件人(from_name)。
但仅仅发送代码是不够的;它还必须存储在用户的数据中。毕竟,当用户收到代码并将其发回作为确认时,你需要验证其正确性。
为了做到这一点,我们将使用twofa ,我们在前面谨慎地创建了这个模型。如果这是第一次提交代码,你必须用它属于哪个用户的信息来创建它。在重复使用的情况下,有必要对现有的条目进行修补,说明其ID和新的代码。
该阶段的最后一步是使用 Raise Error块来返回一个关于发送代码到电子邮件的信息。
代码关联性检查
值得注意的是额外的安全性,保护代码不受平庸的枚举的影响。明智的做法是限制输入尝试的数量,它们的频率,以及提交代码的寿命。我们不会分析所有这些例子;安全要求对于每个项目都是独立的,可能包括许多不同的条件。我们只限于按代码的有效期来检查代码的相关性。
让我们用 Current date & time块来获取当前时间。把它连接到B 参数的 Date & time difference块的参数。我们将使用 UpdatedAttwofa 模型的字段作为参数A 。
结果是,我们得到 Time span- 两个时间点之间的差异。剩下的就是检查这个差异是否超过了某个选定的值。在我们的例子中,这个值是5分钟,我们将其设置为静态值B 。 Greater块的静态值。
该 If-Else块将使用比较结果来进一步指导进程。如果 True(差距超过5分钟),该过程将返回到发送信件的步骤;用户将收到一个更新的代码。在这种情况下 False(代码是新鲜的、最新的),将可以继续检查这个代码。
代码审查
认证的最后阶段是检查收到的代码。
该 Equal块必须验证用户传入的代码与存储在与该用户相关的twofa 模型中的代码相匹配。如果不是这样,并且代码指定不正确(If-Else -> False),那么你需要显示一个错误信息(Raise Error, Message = Code is wrong).如果比较确认了匹配,你可以进入最后的认证阶段。
要做到这一点,我们使用 Auth: Authentication块,获得用户的信息和他的授权令牌。我们把它们传递给 End块,作为成功认证的结果。
创建一个端点
业务流程已经被创建,但还不能使用。你需要创建一个将运行该业务流程的端点。
一个合理的解决方案是使用默认的认证端点(POST /Auth)。替换掉它的业务流程并安装刚刚创建的那个就足够了。因此,简单认证将被禁用,而双因素认证将被使用。
发布和测试
这样就完成了双因素认证的创建。你可以发布结果,并在行动中检查它。为此,使用Swagger ,可以通过点击Project API 部分的Preview 按钮中的部署计划的名称来访问它。
只需在列表中找到所需的端点,输入用户数据,用Execute 按钮开始执行。如果在测试过程中发现任何错误,那么返回到业务流程并进行必要的修改。