更改 ASP.NET Core 中的电子邮件工作流程
Change email workflow in ASP.NET Core
如果用户想更改为新的电子邮件地址,我使用:
var token = await _userManager.GenerateChangeEmailTokenAsync(user, newEmail);
...并发送包含此更改令牌的确认邮件。用户单击电子邮件中的 link,返回站点,现在我需要更改电子邮件。
但是,我不知道新的电子邮件地址。
我经历了确认邮件循环的麻烦,所以我想使用它。再次询问电子邮件可能会导致用户无法访问其帐户的错误输入,这也是用户的另一个障碍,并且需要为我维护更多代码。
明显的解决方案:
- 再次请求(冒着输入错误的风险,使邮件循环毫无意义)
- 将新电子邮件地址存储在
User.NewEmailTemp
中(哎呀,想保持这个无状态)
- 将其包含在电子邮件的 link 中(安全性差!)
可能有更好的方法。更改令牌包含一堆数据,包括包含新电子邮件地址的 "purpose"。我能以某种方式 extract/decode 目的,还是作为散列过程的一部分被破坏?
答案就是坚持。无状态并不是真正的选择。但是,这并不意味着您必须用它来污染用户子域。例如,您可以创建一个单独的实体,如 EmailChangeRequest
,其中包含新电子邮件、令牌和可能的时间戳(主要用于 pruning/expiration)的道具。此处的令牌不是用于验证,而是用于查找,因此可以将其视为 table.
上的键
总而言之,当用户单击 link 时,您通过令牌查找请求,从中获取新电子邮件,然后使用该新电子邮件和令牌。
如果您真的反对任何形式的持久性,我以前曾亲自尝试过 JWT-esque 方法。我说“-esque”是因为传递一个完整的加密和签名的 JWT 作为查询或路由参数将会产生 非常 长的 URL 用于您的确认 links,也许甚至接近请求限制。相反,我所做的是砍掉 JWT 的 header,因为 header 主要用于 cross-client 通信。在这种情况下,我可以安全地假设一个加密方法和发行者,这是不必要的。
我做的另一个改变是使用 TOTP-style 令牌而不是默认使用的加密哈希。这有助于进一步减小 JWT 令牌的大小,并且由于我正在加密 JWT 本身,所以如果内部令牌本身被加密并不那么重要。 email确认之类的token provider可以easily customized in ConfigureServices
, and there's built-in TOTP token providers可以用,所以这个也是比较low-friction.
我仍然认为保留它不一定是坏事,尤其是当您在用户子域之外使用单独的实体时。但是,如果您不想走那条路,伪 JWT 方法可能更适合您的需求。
如果用户想更改为新的电子邮件地址,我使用:
var token = await _userManager.GenerateChangeEmailTokenAsync(user, newEmail);
...并发送包含此更改令牌的确认邮件。用户单击电子邮件中的 link,返回站点,现在我需要更改电子邮件。
但是,我不知道新的电子邮件地址。
我经历了确认邮件循环的麻烦,所以我想使用它。再次询问电子邮件可能会导致用户无法访问其帐户的错误输入,这也是用户的另一个障碍,并且需要为我维护更多代码。
明显的解决方案:
- 再次请求(冒着输入错误的风险,使邮件循环毫无意义)
- 将新电子邮件地址存储在
User.NewEmailTemp
中(哎呀,想保持这个无状态) - 将其包含在电子邮件的 link 中(安全性差!)
可能有更好的方法。更改令牌包含一堆数据,包括包含新电子邮件地址的 "purpose"。我能以某种方式 extract/decode 目的,还是作为散列过程的一部分被破坏?
答案就是坚持。无状态并不是真正的选择。但是,这并不意味着您必须用它来污染用户子域。例如,您可以创建一个单独的实体,如 EmailChangeRequest
,其中包含新电子邮件、令牌和可能的时间戳(主要用于 pruning/expiration)的道具。此处的令牌不是用于验证,而是用于查找,因此可以将其视为 table.
总而言之,当用户单击 link 时,您通过令牌查找请求,从中获取新电子邮件,然后使用该新电子邮件和令牌。
如果您真的反对任何形式的持久性,我以前曾亲自尝试过 JWT-esque 方法。我说“-esque”是因为传递一个完整的加密和签名的 JWT 作为查询或路由参数将会产生 非常 长的 URL 用于您的确认 links,也许甚至接近请求限制。相反,我所做的是砍掉 JWT 的 header,因为 header 主要用于 cross-client 通信。在这种情况下,我可以安全地假设一个加密方法和发行者,这是不必要的。
我做的另一个改变是使用 TOTP-style 令牌而不是默认使用的加密哈希。这有助于进一步减小 JWT 令牌的大小,并且由于我正在加密 JWT 本身,所以如果内部令牌本身被加密并不那么重要。 email确认之类的token provider可以easily customized in ConfigureServices
, and there's built-in TOTP token providers可以用,所以这个也是比较low-friction.
我仍然认为保留它不一定是坏事,尤其是当您在用户子域之外使用单独的实体时。但是,如果您不想走那条路,伪 JWT 方法可能更适合您的需求。