API服务是否应该发送用户激活电子邮件或客户端应用程序?

时间:2014-05-22 05:13:47

标签: api rest activation

我正在尝试开发REST API Web服务。我有一个关于如何处理用户激活电子邮件的问题。目前,API服务处理电子邮件发送。

以下是我目前的流程:

  1. 用户通过客户端应用程序注册
  2. 客户端应用程序POST到API服务
  3. API服务验证并将用户添加到数据库
  4. API服务向用户发送激活链接
  5. 用户点击激活链接,将其带到客户端应用程序激活页面
  6. 客户端应用程序激活页面POST到API服务
  7. 完成
  8. 以下是我目前看到的问题:

    由于API服务当前正在发送电子邮件,因此客户端应用程序无法控制电子邮件的外观。电子邮件中可能存在应指向客户端应用程序的URL。


    另一个选项是发送激活电子邮件而不是API服务,它会将激活密钥返回给客户端应用程序。然后,客户端应用程序将能够将激活电子邮件发送给用户。

    我在此策略中遇到两个问题:

    • 安全性,因为激活密钥现在公开给客户端应用程序。
    • 不干,因为每个客户都可以负责发送电子邮件。

    您认为处理此问题的最佳方式是什么?

    我想允许客户端应用程序自定义其电子邮件,以及包含特定于客户端的URL(激活页面)。

8 个答案:

答案 0 :(得分:11)

TL; DR

为开发人员创建一个小型服务来创建模板,让他们在POST到您的激活API时声明他们想要使用哪个模板


问题摘要:

  • 每个客户端应用程序的电子邮件需要看起来不同
  • 发送邮件应该实施一次
  • 解决方案应该是安全的

每次都不需要让电子邮件看起来与众不同。因此,无需使用POST请求发送电子邮件格式。

相反,可以执行以下任一操作:

1 创建一个单独的API端点来定义模板,并让客户端应用程序在发布激活请求时选择其中一个。

这并不完全安全,如果您想从客户端应用程序接受HTML,至少会带来一定的挑战。

推荐的解决方案:

2 为开发人员(在他们获取API密钥的同一网站上)创建一个工具,接受创建它们的模板和辅助工具。在发布激活请求时,客户端应用可以选择其中一个。请求正文的片段如下:

...
"template": "foobar-app",
"fields": {
    "title": "Welcome to foobar app",
    "username": "jim78"
}
...

允许字段中没有HTML。

这使您可以使用开发人员准备的预定义模板,这些模板可供您的电子邮件发送服务使用,客户端应用程序中的任何错误都不会导致电子邮件变得不安全。此外,您还可以获得可以处理和测试模板的位置。 (开发人员可以将它们发送给自己进行调试 - 制作电子邮件模板非常糟糕,让我相信)

您将来能够更好地支持您的开发人员/客户,并准备一组在多个邮件客户端中测试的工作模板。

答案 1 :(得分:2)

关于安全和信任的观点。通常,您发送的激活电子邮件包含具有激活码的URL链接。电子邮件的目的是验证电子邮件是否有效以及用户是否有权访问该电子邮件。用户收到验证链接的唯一方法是通过电子邮件。

如果您将激活链接传回客户端,则有权访问您的API的任何人都可以访问激活码。如果他们可以访问该链接,则可以绕过验证过程。如果您有一个Web应用程序,这非常简单,因为他们只需要进入浏览器开发人员模式即可查看链接。如果您有一个胖客户端,那么如果您不使用像https这样的加密,他们可以窥探网络。如果他们是专用的,他们也可以反编译您的二进制文件(这就是为什么你不在你的二进制文件中存储密钥)。

后端永远不应该信任客户端来实现安全过程,因为它永远不会知道它何时被泄露。安全和正确的方法是在服务器端执行激活电子邮件。 另一种看待这种情况的方法是,它类似于客户说"是的,用户已经过身份验证,因此请提供所有数据"

至于模板,上面有很多好的答案。我建议有一个模板目录和一个可以替换的参数列表。

答案 2 :(得分:2)

所以我认为这样做的方式是一个很好的方式。因此,我采用了JSON Web令牌如何工作的方法,并将其应用于我的激活链接。我将解释它是如何工作的:

我有2个Web服务器,一个处理REST API,另一个处理spa。

因此用户注册,并将请求发送到API。然后将响应返回到SPA,此时如果成功向SPA后端发送请求,该后端使用用户的凭证签署令牌,则令牌的目的(这种情况是验证电子邮件地址)它的到期日。

此令牌被发送到用户的电子邮件地址,但是在REST服务器上有一个接收路由将解码令牌,如果有效,则验证电子邮件地址。

这确实意味着技术上只有第一方客户可以验证电子邮件地址,因为他们是唯一可以知道您的密码的人。如果您的秘密是免费发放的,那么任何人都可以验证他们的电子邮件地址的问题。

我希望这有帮助!

编辑:另一种方法是传递一个内置在把手中的模板或者用于交换实际值变量的东西。然后让REST api呈现它,并通过电子邮件发送它。 (这可能是最好的方式imo haha​​)

答案 3 :(得分:1)

您的API可能有一个IEmailBodyFormatter对象,该对象作为参数传递给您的API调用....

答案 4 :(得分:1)

我将第2步扩展到发送到服务器的其他后期数据:

"mail":{
  "placeholder":"someStringChoosenByClientWhichWillBeReplaceByActivationCode",
  "subject":"Hey there, please activate",
  "ishtml":false,
  "body":"SSdtIHRyeWluZyB0byBkZXZlbG9wIGEgUkVTVCBBUEkgd2ViIHNlcnZpY2UuIEkgaGF2ZSBhIHF1ZXN0aW9uIGFib3V0IGhvdyB0byBoYW5kbGUgdXNlciBhY3RpdmF0aW9uIGVtYWlsLiBDdXJyZW50bHksIHRoZSBBUEkgc2VydmljZSBoYW5kbGVzIGVtYWlsIHNlbmRpbmcu"
  "attachments":[
                  {
                     "content-type":"image/png",
                     "filename":"inline_logo.png",
                     "content":"base64_data_of_image"
                  }
                ]
}

这将允许客户端完全控制已发送的消息,但激活程序(邮件生成和交付)仍由服务处理。

客户端可以为每个用户生成除激活密钥之外的所有内容(例如,使用“Hello XYZ”作为主题)。

我不确定允许html-Mails("ishtml":false,)是否是一个好主意,这取决于您的应用程序以及您希望花费多少时间来实现它。

答案 5 :(得分:0)

允许客户端管理自己的电子邮件模板。当他们发布新用户注册时,允许他们指定要使用的模板。然后您的应用程序正在发送电子邮件消息,但客户端可以控制它的外观。

POST /email-templates
{
    "subject": "Complete Your Registration",
    "body": "<html>Follow this link to complete your registration: {activationLink}. It is valid for 45 minutes.</html>"
}

POST /registration-requests
{
    "name": "John Q. Public",
    "emailTemplate": "/email-templates/45"
}

答案 6 :(得分:0)

我认为正确的方法是为客户端公开激活密钥以执行任何操作。

您还可以添加另一个端点来为用户发送激活密钥。

返回用户。 (使用User/{userid}等网址和其他资源网址User/{userid}/ActivationKey)

User (POST) 

这可以返回当前用户和其他资源,如电子邮件,激活等。 有关密钥的信息(如日期,到期等)

User/{userid}/ActivationKey

从那里你只要你愿意就可以扩展它:

预览激活电子邮件:

User/{userid}/ActivationKey/Email (GET) 

使用电子邮件的模板,smtp服务器等更新激活电子邮件。 :

User/{userid}/ActivationKey/Email (PUT)

创建(并发送)激活电子邮件,可能包含发送日期或其他发送选项(text-html版本等):

User/{userid}/ActivationKey/Email (POST)

您可以列出所有已发送的电子邮件,并在必要时在另一个端点中预览它们。

User/{userid}/Emails (GET)
User/{userid}/Emails/{emailid} (GET)

答案 7 :(得分:0)

我加入nauktur,让客户向您发送电子邮件模板。 (和+1谈论一种测试方法,因为我同意邮件“开发”的可怕性。)

但为什么这么复杂?客户端应用程序意味着开发人员,所以为什么不让他们为您提供默认模板(使用HTML),如果他们想要,让他们玩,并将他们喜欢的版本发回给您? 这对你来说不是很多工作(只是客户端表中的一个新字段和一个新的路由),它给了他们很多选择。

这是一个基本的例子,我们将公开一些参数,以便他们可以使用HTML而不需要知道它们:

  • app.name
  • app.description
  • activation_code
  • user.* 注册信息

基本模板

{
  title: "Your activation code for %{app.name}",
  body: "<p>Hi, you've been registered on %{app.name}.
    <p>%{app.description}</p>
    <p>Follow <a href="%{activation_code}">this link to confirm your inscription</a>."
}

注册新模板

然后客户说:“我希望有一个更简单的邮件,但我想要他的名字!” [PUT] /api/email/templates/client_id

{
  title: "Your activation code",
  body: "<p>Hi %{user.fullname}, Follow <a href="%{activation_code}">this link to confirm your inscription</a>."
}

你走了。让他们玩HTML,它允许更个性化的方式 除了他们在客户身上的形象,如果他们陷入困境,他们就是他们的客户,这没有什么害处。

安全问题

有人指出,攻击者可以访问客户端应用程序的令牌,可能会在模板中注入恶意内容。首先,如果令牌泄漏,风险已经很高,这是您最后的担忧。尽管如此,如果你害怕这一点,禁止使用img代码并使a代码的内容与href属性相匹配可以解决您的问题。