如何在iOS上通过电子邮件进行无缝的“无密码”身份验证。

Apple平台上的邮件和日历集成

在macOS和iOS上查看电子邮件时,邮件会在[检测到的日期和时间]下划线 。您可以与他们互动以创建新的日历事件。如果您在“日历”中打开此类活动,则会在其扩展详细信息中看到“在邮件中显示”链接。单击此链接可将您带回到原始电子邮件。此功能可以追溯到iPhone的发布。它将被纳入当年的 [Mac OS X版本(Leopard)中,] 这将标志着许多移动功能中的第一个进入台式机。

如果要将“魔术” URL复制到粘贴板并在文本编辑器中查看,则会看到以下内容:

"message:%3C1572873882024.NSHIPSTER%40mail.example.com%3E"

经验丰富的iOS开发人员将立即意识到使用 [自定义URL方案]。其中精通网络的用户可以对主机进行百分比解码,并识别出它类似于电子邮件地址,但事实并非如此。

因此,如果没有电子邮件地址,我们在这里看什么?
这是另一个不同的电子邮件字段,称为Message-ID

另外,如果你想一起进阶,不妨添加一下交流群[1012951431],选择加入一起交流,一起学习。期待你的加入!(进群可领取学习礼包)

消息ID

[RFC 5322§3.6.4]规定,每封电子邮件应该 具有“消息ID:”字段包含单个唯一消息标识符。该标识符的语法本质上是一个带有尖括号(< >)的电子邮件地址。

尽管该规范未包含任何有关生成良好Message-ID的规范性指导,但 1998年的[IETF草案草稿]还是很不错的。

让我们看一下如何在Swift中执行此操作:

生成随机消息ID

前述文档中描述的第一种技术涉及生成带有64位随机数的随机消息ID,该消息ID带有时间戳,以进一步减少冲突的机会。我们可以使用Swift 5内置的随机数生成器API和[String(_:radix:uppercase:)初始化]程序来轻松完成此操作 :

import Foundation

let timestamp = String(Int(Date().timeIntervalSince1970 * 1000))
let nonce = String(UInt64.random(in: 0..<UInt64.max), radix: 36, uppercase: true)
let domain = "mail.example.com"

let MessageID = "<\(timestamp).\(nonce)@\(domain)>"
//"<[email protected]>"

然后,我们可以将生成的Message-ID与关联的记录一起保存,以便以后链接到它。但是,在许多情况下,一种更简单的选择是使消息ID具有确定性,并且可以从其现有状态进行计算。

生成确定性消息ID

考虑符合[Identifiable协议]且其关联`ID`类型为 [UUID]的记录结构 。您可以这样生成消息ID:

import Foundation

func messageID<Value>(for value: Value, domain: String) -> String
where Value: Identifiable, Value.ID == UUID
{
return "<\(value.id.uuidString)@\(domain)>"
}
import Foundation
import CryptoKit

let body = #"""
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
"""#

let digest = Data(SHA256.hash(data: body.data(using: .utf8)!))
.map { String($0, radix: 16, uppercase: true) }
.joined()

let domain = "ADF"
"<\(digest)@\(domain)>"
// "<F52380112175FCE8ECF2731C193EB8A7CC8642E53C68D292CD88531D42F145@mail.example.com>"

 移动深层链接

iOS和macOS上的常规Mail客户端都将尝试`message:`通过启动到前台并尝试使用编码的Message-ID字段打开消息来使用自定义方案打开URL 。

生成具有消息ID的邮件深层链接

掌握了Message-ID之后,最后的任务是创建一个深层链接,您可以使用该深层链接将Mail打开到关联的消息。唯一的技巧是 在URL中对消息ID 进行 [百分比编码]。您可以使用[方法]来执行此操作 ,但是我们更愿意将所有操作委托给-这具有进一步的优势,即无需使用[格式字符串]就可以完整构建URL 。[`adding PercentEncoding(withAllowedCharacters:)`][`URLComponents`]

import Foundation

var components = URLComponents()
components.scheme = "message"
components.host = MessageID
components.string!
// "message://%3C1572873882024.NSHIPSTER%40mail.example.com%3E"

据我们所知,自定义`message:`方案后是否存在双斜杠不会对邮件深层链接解析产生任何影响。

打开邮件深层链接

如果您`message:`在iOS上打开URL,并且可以从 其中一个帐户的inbox轻松访问链接的消息,则Mail将立即启动该消息。如果找不到该消息,则该应用程序将启动并在后台异步加载该消息,并在可用时将其打开。相比之下,尝试在macOS上打开到尚未加载的邮件的邮件深层链接会导致显示警报模式。因此,我们建议仅在iOS上使用邮件深层链接。例如, [飞行学校]使用无密码身份验证系统来执行此操作。要访问书籍的电子副本,请输入用于购买书籍的电子邮件地址。提交表单后,iOS上的用户将看到一个深层链接,用于打开指向包含“魔术登录链接”✨的电子邮件的Mail应用程序。

其他系统可能使用消息ID通过[通用链接]简化其本机应用或网站的无密码身份验证 ,或者将其合并为2fa策略的一部分 (因为[出于此目的,不再认为][sms是安全的])。如果您在Web应用程序中使用Rails,则 [ActiveMailer拦截器]提供了一种方便的方式来Message-ID为无密码验证流注入字段。


与苹果平台上如此众多的私人集成(仍然是第一方应用程序的专有领域)不同,“在邮件中显示”的秘密之处在于我们所有人都能参与进来。尽管没有记录,但是由于该功能与系统的深度集成以及植根于基本Web标准中,因此该功能不太可能很快被删除。

从[浏览器供应商], [社交媒体公司]到 [政府](甚至有时甚至是苹果[公司)的]每个人都 试图拆开开放的网络并控制我们可以看到和执行的操作时,很高兴得知电子邮件 [将近50年了],保持互联网自由和分散的能力仍然坚决。

翻译地址: https://nshipster.com/message-id/

11-09 21:03