经过前面几节内容,用户可以使用我们的Greenlight API注册一个帐户,但我们不确定他们在注册过程中提供的邮件地址是否真的属于他们。因此,在本书的这一部分,将实现的功能是可以确认用户使用的邮箱地址是真是有效的,实现的方式就是在用户注册时,在发送欢迎邮件中添加“账号激活”信息。
激活账号的理由有很多,但主要的目的还是为了防止滥用非法邮箱注册。先大概说下帐户激活过程:
1、作为新用户注册的一部分,我们将创建一个加密的随机激活token,该token用户是无法猜测的。
2、我们将该token的哈希值存在一张新的token表中,表包含用户ID和token过期时间。
3、我们将在用户注册时,在发送欢迎邮件中添加激活token并发给用户。
4、然后用户提交token到PUT /v1/users/activated接口。
5、如果token的哈希值在token表中存在并且没有过期,我们将更新用户的激活状态为true。
6、最后删除token表中的激活token,以免被多次使用。
后面的内容你将学习到:
- 如何通过验证新用户邮箱来实现一个安全的“账户激活”流程。
- 使用Go的crypto/rand和encoding/base32包生成安全的随机token。
- 使用crypto/sha256生成哈希值。
- 数据库关联表的使用,包括设置外键以及SQL的JOIN查询。
创建tokens表
首先在数据库中创建tokens表来存储用户的激活token。如果你跟随本书操作,执行以下命令创建一对数据库迁移文件:
$ migrate create -seq -ext=.sql -dir=./migrations create_tokens_table
/Users/wangmingjun/Projects/greenlight/migrations/000005_create_tokens_table.up.sql
/Users/wangmingjun/Projects/greenlight/migrations/000005_create_tokens_table.down.sql
然后分别在“up”和“down”迁移文件中添加以下内容:
File: migrations/000005_create_tokens_table.up.sql
CREATE TABLE IF NOT EXISTS tokens(
hash bytea PRIMARY KEY,
user_id bigint NOT NULL REFERENCES users ON DELETE CASCADE,
expiry timestamp(0) with time zone NOT NULL,
scope text NOT NLL
)
File: migrations/000005_create_tokens_table.down.sql
DROP TABLE IF EXISTS tokens;
我们快速浏览下tokens表中各个列,并解释下其意思:
-
hash列包含激活token的SHA-256值。需要指出的是存储在数据库中的值并不是激活token本身而是其哈希值。在数据库中存储敏感信息时,存储其哈希值的目的是防止数据库泄漏,导致敏感信息都泄漏。因为激活token和用户密码不一样,它本身就是一个随机值,因此使用快速算法SHA256创建hash值就足够了,而不是使用bcrypt其速度慢。
-
user_id列包含激活用户的ID,我们使用REFRENCES users语法来创建表的外键与users表对应,确保use_id列的值在users表中也有对应的值。我们使用ON DELETE CASCADE语法表示,在删除user表中的数据时,自动删除tokens表中关联的数据(id值相等)
ON DELETE CASCADE的另一个对应语法是ON DELETE RESTRICT,它表示如果用户在tokens表中存在关联数据时,需要删除tokens后才能删除user表中的用户。如果使用ON DELETE RESTRICT,必须人工删除用户关联的任意tokens才能删除用户信息。
-
expiry列保存token过期时间。从安全角度看设置一个较短的过期时间是必要的,它能降低暴力破解token的窗口期。当用户收到一个token但没有使用它,而他们的邮件帐户后来被泄露时就起作用了。通过设置较短的时间限制,可以减少使用被泄露的token时间窗口。
-
当然,这里的安全风险需要与可用性进行权衡,我们希望过期时间足够长,以便用户能够在空闲时激活帐户。在我们的例子中,我们将激活令牌的过期时间设置为从创建令牌的那一刻起的3天内。
-
最后scope列表示token的使用范围。后面我们还要创建认证token,大部分的代码、存储方式和这里的激活token是一样的。因此不需要单独再创建新的表,使用同一张表来存储不同用途的token,scope列表示token的用途。
经过上面的文字说明,你可以用下面的命令执行“up”迁移:
$ migrate -path=./migrations -database=$GREENLIGHT_DB_DSN up
接下来的内容将是激活token的创建,以及向用户发送激活token等,将在下一篇文章中呈现。
网友评论