简单的账户注册服务如何设计

  |  

摘要: 本文以一个简单的账户注册服务如何设计的问题看一下作为程序员如何理解需求,拿到一个需求后会怎样设计系统。

【对数据分析、人工智能、金融科技、风控服务感兴趣的同学,欢迎关注我哈,阅读更多原创文章】
我的网站:潮汐朝夕的生活实验室
我的公众号:潮汐朝夕
我的知乎:潮汐朝夕
我的github:FennelDumplings
我的leetcode:FennelDumplings


用户角度的账户注册

作为一个用户,注册账户的时候往往需要做以下事情:提供一个未被使用的账号 ID 提供一个未被使用的 email 地址提供一个任意的显示名称设置安全密码,并重复输入以确认输入验证码前往邮箱查收激活链接并单击激活账号登录。

账号的 ID 和 email 地址都可以用来唯一地标识某个账户,而显示名称则用来显示在页面上,方便浏览。

注册的时候用户还需要输入两次密码,以确保没有输错。系统则需要负责检查 ID 和 email 的唯一性,验证两次输入的密码是否一致。

验证码是由系统随机生成的只能由肉眼识别其内容的图片,可以有效防止机器恶意批量注册,若输入正确的验证码信息,系统则会进行检查,如果验证码错误,系统会生成并返回新的验证码。

一旦所有检查都没问题了,系统就会生成一个激活链接,并发送到用户的邮箱中。单击激活链接后,账户就被激活了,这时账户注册完成,用户可以进行登录。

对于一个账户注册服务,还需要考虑一些安全因素。例如,需要在服务器端密文地保存密码,检查密码的强弱程度,更进一步则需要考虑验证码的失效时间,激活链接的失效时间,等等。

软件工程角度的账户注册

前面了解了用户视角的账户注册服务,下面看一下软件工程角度的账户注册服务的需求到底是什么。

需求用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
主要场景: 

1. 用户访问注册页面
2. 系统生成验证码图片
3. 用户输入想要的 ID、email 地址,想要的显示名称、密码、确认密码
4. 用户输入验证码
5. 用户提交注册请求
6. 系统检查验证码
7. 系统检查 ID 是否已经被注册,Email 是否已经被注册,密码和确认密码是否一致
8. 系统保存未激活的账户信息
9. 系统生成激活链接,并发送至用户邮箱
10. 用户打开邮箱,访问激活链接
11. 系统解析激活链接,激活相关账户
12. 用户使用 ID 和密码登录

扩展场景:
4a. 用户无法看清验证码,请求重新生成
1. 调到步骤 2
6a. 系统检测到用户输入的验证码错误
1. 系统提示验证码错误
2. 跳转到步骤 2
7a. 系统检测到 ID 已经被注册,或者 Email 已经被注册,或者密码和确认密码不一致
1. 系统提示相关错误信息
2. 跳转到步骤 2

该注册账户用例包含了一个主要场景和几个扩展场景。该用例的角色只有两个:用户和系统。

“主要场景”描述了用户如何与系统一步一步地交互,并且成功完成注册。“扩展场景”则描述了一些中途发生意外的情形。

该用例没有涉及非功能性需求(如安全性),也没有详细定义用户界面,用例也不会告诉我们使用何种技术。

界面模型

简要设计

接口

系统对外的接口。从需求用例中可以看到,系统对外的接口包括生成验证码图片、处理注册请求、激活账户以及处理登录等。

AccountService

  • generateCaptchaKey()
    • generateCaptchaImage(captchaKey: String)
    • SignUp(signUpRequest: SignUpRequest)
    • activate(activationNumber: String)
    • login(id: String, password: String)
  • SignUpRequest
    • id
    • email
    • diapleyName
    • password
    • confirmPassword
    • captchaKey
    • captchaValue
    • getId()
    • setId()

generateCaptchaKey() 和 generateCaptchaImage() 方法:Captcha 就是验证码。每个 Captcha 都需要有一个 key,根据这个 key,系统才能得到对应的验证码图片以及实际值。因此,generateCaptchaKey() 会生成一个 Captcha key,使用这个 key 再调用 generateImage() 方法就能得到验证码图片。验证码的 key 以及验证码图片被传送到客户端,用户通过肉眼识别再输入验证码的值,伴随着 key 再传送到服务器端验证,服务器端就可以通过这个 key 查到正确的验证码值,并与客户端传过来的值进行比对验证。

SignUpRequest 包含了注册用户所需要的信息,包括 ID、email、显示名称、密码、确认密码等。这些信息伴随着 Captcha key 和 Captcha value 构成了一个注册请求。

signUp() 方法接收 SignUpRequest() 对象,进行验证,如果验证正确,则创建一个未被激活的账户,同时在后台也需要发送一封带有激活链接的邮件。

activate() 方法接收一个激活码,查找对应的账户进行激活。

账户激活之后,用户可以使用 login() 方法进行登录。

模块结构

定义了系统核心的接口之后,基于功能分割和方便复用的原则,再对系统进一步进行划分,在 Java 中一般可以基于包名划分模块。

1
2
3
4
5
6
7
com.czx.account.web
|
| |---> com.czx.account.persisit
\|/ |
com.czx.account.service --|---> com.czx.account.captcha
|
|---> com.czx.account.email

com.czx.account.service:系统的核心,它封装了所有下层细节,对外暴露简单的接口。这实际上是设计模式中的 Facade 模式。

com.czx.account.web:模块包含所有与 web 相关的内容。它直接依赖于 com.czx.account.service 模块,使用其提供的服务。

com.czx.account.persisit:处理账户信息的持久化,包括增、删、改、查等,根据实现,可以基于数据库或者文件。

com.czx.account.captcha:处理验证码的 key 生成、图片生成以及验证等,这里需要第三方的类库来帮助实现这些功能。

com.czx.account.email:处理邮件服务的配置、激活邮件的编写和发送等工作。

总结

到目前为止,我们已经了解了账户注册服务的需求、大概的界面、简单的接口设计以及模块的职责划分,就差实际编写代码了。


Share