除非网站上所有的数据和功能都是公开的,否则你一定会需要用户、角色和权限系统。不同的用户会有不同的权限,你需要识别出请求来自哪个用户。

想对用户请求进行识别,就需要前端在向服务器发送请求时携带的身份标识信息,一般均采用 Token 机制来实现,通过 Cookie/Header 发送。Token 可以是通过对称密钥加密的,也可以是采用私钥签名的。主要目的是阻止第三方伪造 Token 以其他用户身份访问网站。

  • 对称加密
Token = 对称加密([用户ID,时间戳...], 密钥)

密钥是保密的,只存在于服务器上,Token 的生成与解析由服务器负责,客户端也无法解密 Token。Token 中通常只有 userId 和 timestamp。

  • 非对称加密 (JWT)
Identify = base64.encode([用户ID,时间戳...])
Token = Identify + 签名(哈希(Identify), 私钥)

私钥是保密的,只存在于服务器上,Token 的生成由服务器负责,通常由原始用户身份信息 Identify 和签名两部分组成,用户身份 JSON 字符串,通过 base64 算法进行编码作为 Identify,由于 Identify 长度不固定,可用与客户端约定好的哈希算法进行运算,再用私钥进行签名。

这种方法生成的 Token 并不是加密的,客户端甚至第三方拿到 Token 后都可以解析出其中的用户身份信息。

客户端持有相对应的公钥,可对 Token 进行签名验证,验证此 Token 是否是具有私钥的服务器生成的,并可以从 Token 中解析出原始用户信息。Token 可携带很多用户信息,甚至可包含用户角色权限等信息。

[Identify, signature] = split(Token)
签名验证(哈希(Identify), signature, 公钥)
[用户ID,时间戳...] = base64.decode(Identify)

对称加解密、非对称加解密、签名、哈希等算法都属于密码学范畴,之前有介绍过 Golang 语言的各种密码学方法。常见密码学方法

⚠️重要更新:不要用 UUID 作为 Token,UUID 在设计上保证唯一性,但不保证随机性和不可预测性,理论上来说,恶意用户有可能得到你服务器的 mac 地址,并进行时间戳同步,还是有比较大的可能预测后续生成的 UUID 序列,作为 Token 不安全。

如果感兴趣还可以看一下几种常见的Token生成方法,如何快速实现用户认证服务(里面介绍了注册和登录的基本实现方法),还有Golang中常见密码学代码(里面介绍了几种常见的加解密、信息摘要、签名等具体实现代码)。