How do I generate a unique token (for e-mail verification)?

huangapple go评论77阅读模式
英文:

How do I generate a unique token (for e-mail verification)?

问题

我想实现一个系统,在用户注册后,用户将收到一封包含验证链接的电子邮件,以验证该电子邮件是属于该用户的。

我生成用于验证电子邮件的令牌的方法如下:

import (
	"crypto/rand"
	"encoding/base64"
)

func generateToken() (string, error) {
	b := make([]byte, 35)
	_, err := rand.Read(b)
	if err != nil {
		return "", err
	}
	return base64.URLEncoding.EncodeToString(b), nil
}

但我想问的是,这种方法可行吗?如何确保该方法生成的所有令牌都是唯一的?

实现这个系统的常规方法是什么?

请给我一些想法,并告诉我这种生成令牌的方法是否好。

谢谢。

英文:

I want to implement a system that after user signs up, user will receive an email includes a link to verify this email is for that user.

The way I generate the token for verifying the email is like this:

import (
	"crypto/rand"
    "encoding/base64"
)

func generateToken() (string, error) {
    b := make([]byte, 35)
	_, err := rand.Read(b)
	if err != nil {
    	return "", err
	}
    return base64.URLEncoding.EncodeToString(b), nil
}

But what I want to ask is if this method is OK? How to make all the token generated by this method is unique ?

What is the normal way to implement this system ?

Please give me some ideas and tell me if this method of generating token is good.

Thanks.

答案1

得分: 5

请查看 https://pkg.go.dev/github.com/google/uuid#NewRandom

你可能想考虑将此信息与电子邮件地址一起存储在数据库中,可能还包括过期日期/时间,以便验证信息不会永远保留。你可能只想允许人们在24小时内或7天内进行验证等。可以设置一个定期清理过期和未验证电子邮件的任务。

英文:

Check out https://pkg.go.dev/github.com/google/uuid#NewRandom.

And you may want to consider storing this in a database with the email address and perhaps an expiry date / time so that the verification doesn't stay there forever. You may only want to allow people to verify within 24 hours, or 7 days and so on. Have another job that periodically cleans expired and non-verified emails.

答案2

得分: 2

两点:

  • 不,按照目前的方法,不能保证它们是唯一的。
  • 你不需要所有的令牌都是唯一的。

对这些观点进行详细说明:

你正在处理一组未完成的验证请求。
也就是说:

  1. 用户发出请求;
  2. 你生成一个唯一的验证令牌,并将其存储到某个持久化数据库中。这是为了验证工作而必需的。
  3. 用户收到你的电子邮件,并点击其中包含令牌的链接。此时,你从持久化存储中删除有关此待处理验证请求的信息。

正如你所看到的,任何时候你只有几个未完成的验证请求。因此,这种情况具有两个重要的特性:

  • 你只需要这些未完成请求的令牌彼此不同即可。验证令牌与某个过去(或未来)请求的令牌相同是可以的。
  • 你的令牌必须很难猜测(显然)。我相信你已经理解了这一点。

因此,生成新令牌的方法如下:

  1. 生成一些很难猜测的东西。

  2. 将其与存储在你的存储中的未完成/待处理验证请求的令牌进行比较。

    如果找到一个具有相同令牌的未完成请求,说明发生了冲突,因此返回步骤(1)并重复操作。

    否则,该令牌是可用的,因此继续进行并将有关此请求的数据持久化。

  3. 一旦请求通过验证,从存储中删除它。

生成令牌的确切算法并不重要。我认为使用 UUID 或类似 SHA-256/512 计算的随机数据是可以的。

英文:

Two points:

  • No, the method as presented won't guarantee them to be unique.
  • You don't need to have all your tokens to be unique.

To expand on these points…

You're dealing with a set of outstanding verification requests.
That is:

  1. A request is made by the user;
  2. You generate a unique verification token and store it into some presistent database. This is needed in order for verification to work anyway.
  3. The user receives your e-mail and clicks that link from it which contain your token. At this point you remove the information about this pending verificaton request from your persistent storage.

As you can see, at any given time you only have several outstanding verification requests. Hence this situation has two important properties:

  • You only need the tokens of these outstanding requests be different from one another. It's OK to have a verification token to be the same as that of some past (or future) request.
  • Your tokens have to be hard-to-guess (obviously). I'm sure you already understand that.

So, the approach to generating a new token is as follows:

  1. Generate something hard-to-guess.

  2. Compare it with the tokens bound to the outstanding/pending verification requests persisted in your storage.

    If you find an outstanding request with the same token, you have a collision so go to step (1) and repeat.

    Otherwise the token is OK so proceed with it and persist the data about this request.

  3. Once the request passed verification, remove it from your storage.

Exact algorythm for generating tokens does not matter much. I'd say an UUID or something looking like SHA-256/512 calculated over some random data is OK.

huangapple
  • 本文由 发表于 2016年1月22日 20:41:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/34947001.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定