第5章用户登录服务——5.2 用户登录服务的功能要点

用户登录服务负责用户的注册与登录,这是一个看似非常简单、很容易设计的服务。在学习数据库的过程中,很多同学都做过数据库的各种管理系统课程设计,比如图书馆管理系统、学生成绩管理系统等,使用数据库作为数据存储系统,使用HTTP协议的HTML页面作为用户操作界面。无论哪个管理系统,必不可少的一个功能都是用户注册与登录。当时,大家实现这个功能的方式基本如下。

首先,在数据库中创建一个用户表User来记录用户账号、密码和用户状态等信息,如表5-1所示(注意:用户昵称、头像、个性签名等这里暂不列出,它们不是用户登录服务的重点)。

image-20250322093436569

然后,开发用户注册页面和登录页面。页面元素如下。

  • 账号文本框:用户在此输入账号。
  • 密码文本框:用户在此输入密码。
  • 验证码标签:用户打开页面时,网页随机生成一个验证码并展示。
  • 验证码文本框:用户在此输入验证码。
  • 注册按钮:用户点击后注册。
  • 登录按钮:用户点击后登录。

用户注册的流程如下。

  1. 用户打开注册页面,并在上述三个文本框中依次输入待注册的账号(如abc)、密码(如123456)和验证码。
  2. 用户点击注册按钮,HTTP使用POST方式将用户填入的账号、密码提交到后台。
  3. 后台在User表中查询账号abc是否存在,如果存在,则报错返回;否则,将账号、密码插入 User 表中。SQL 语句为INSERT INTO User(username, password, status) VALUES('abc', '123456', 0)
  4. 插入数据成功后,后台返回给用户”注册成功”的响应信息。

用户登录的流程如下。

  1. 用户打开登录页面,依次输入账号(如abc)、密码(如123456)和验证码。
  2. 用户点击登录按钮,将账号、密码提交到后台。
  3. 后台尝试在User表中将账号为abc、密码为123456且未登录的用户状态更新为“已登录”。SQL 语句为UPDATE User SET status=1 WHERE username='abc' AND password='123456' AND status=0
  4. 如果数据库中有1行数据被更新了,则说明用户存在且密码正确,于是后台返回给用户“登录成功”的响应信息;否则,提示用户“账号/密码错误或账号异常”。

通过这种方式,用户登录服务只需要依赖数据库,且用户注册与登录功能在同一个数据表上执行一条SQL语句就能实现,看似用最简单的方式就可以满足要求。

然而,正规的互联网公司都不可能这么做,因为这种方式虽然简单,但是漏洞百出。

  • 用户ID依赖数据库的自增主键,其值可以反映出目前已注册用户有多少,这属于泄露商业机密。我们应该使用基于时间戳的分布式唯一ID来生成用户ID,具体细节参见第4章。
  • HTTP将用户账号、密码以明文形式传输到后台,如果在网络传输过程中遭到攻击者监听,则会直接造成用户账号、密码的泄露。
  • 后台直接把用户密码保存到数据库中,如果数据库被意外泄露到公网,则等于曝光了用户密码。此外,与用户登录服务相关的工程师可以直接在数据库中查看用户密码,这会降低用户的安全感。如果有“内鬼”工程师利用职务之便使用这些数据做什么事情,后果将难以估量。
  • 需要使用用户账号、密码登录的限定形式,会导致注册与登录成为用户的负担,因为缺少便捷性,用户不得不绞尽脑汁创建并牢记账号与密码。为了减少用户的访问负担,很多互联网产品都提供了各种登录方式,如手机号登录、邮箱登录、第三方(QQ、微信、微博、抖音等)登录。对于同时存在PC端、移动端的互联网产品,用户在登录移动端后还可以扫码登录PC端,比如爱奇艺、支付宝等。总之,用户注册与登录应该越简单越好,一键注册/登录是最好的选择
  • 在微服务架构下,很多后台服务都需要先判断用户是否已登录(即查询用户登录态),于是纷纷从用户登录服务中获取信息。如果使用User表查询用户登录态,则会导致数据库被迅速击垮。实际上,用户登录态是一个热门话题,我们会专门用一整节来介绍其细节(见5.6节)。

如上种种充分说明用户登录服务的设计实现并没有那么简单,它至少需要满足如下技术要求。

  • 密码安全:任何时候都不可以将用户密码暴露给任何人,包括服务设计方。
  • 以多种方式登录:需要具有支持手机号登录、邮箱登录、第三方登录和扫码登录的能力。
  • 支持登录态查询:很多服务都会依赖用户登录态,需要使用高性能、高可用的方式支持这个需求。

总结

为什么正规的互联网公司不会使用账号密码方式来做用户登录服务呢?

  • 用户ID依赖数据库的自增主键,其值可以反映出目前已注册用户有多少,这属于泄露商业机密。我们应该使用基于时间戳的分布式唯一ID来生成用户ID,具体细节参见第4章。
  • HTTP将用户账号、密码以明文形式传输到后台,如果在网络传输过程中遭到攻击者监听,则会直接造成用户账号、密码的泄露。
  • 后台直接把用户密码保存到数据库中,如果数据库被意外泄露到公网,则等于曝光了用户密码。此外,与用户登录服务相关的工程师可以直接在数据库中查看用户密码,这会降低用户的安全感。如果有“内鬼”工程师利用职务之便使用这些数据做什么事情,后果将难以估量。
  • 需要使用用户账号、密码登录的限定形式,会导致注册与登录成为用户的负担,因为缺少便捷性,用户不得不绞尽脑汁创建并牢记账号与密码。为了减少用户的访问负担,很多互联网产品都提供了各种登录方式,如手机号登录、邮箱登录、第三方(QQ、微信、微博、抖音等)登录。对于同时存在PC端、移动端的互联网产品,用户在登录移动端后还可以扫码登录PC端,比如爱奇艺、支付宝等。总之,用户注册与登录应该越简单越好,一键注册/登录是最好的选择。
  • 在微服务架构下,很多后台服务都需要先判断用户是否已登录(即查询用户登录态),于是纷纷从用户登录服务中获取信息。如果使用User表查询用户登录态,则会导致数据库被迅速击垮。

设计用户登录服务需要满足哪些技术要求呢?

  • 密码安全:任何时候都不可以将用户密码暴露给任何人,包括服务设计方。
  • 以多种方式登录:需要具有支持手机号登录、邮箱登录、第三方登录和扫码登录的能力。
  • 支持登录态查询:很多服务都会依赖用户登录态,需要使用高性能、高可用的方式支持这个需求。