Token
Token是一种分布在客户端的无状态用户登陆证明,其诞生场景如下所述。
服务器 无法保留或不愿意保留(服务器开销)用户的登陆状态,要想确认先后两次发来的两条消息来自同一个用户,无非以下两种情况:
- 用户每次发送请求都带上自己的认证ID和敏感信息,如账号和密码;服务器每次处理处理请求时都从服务器数据库验证用户身份以确定用户的登陆状态;
- 基于Session等方式记录用户的登陆信息;
很显然,上面两种方式,第一种方式容易造成用户敏感信息泄露;而第二种方式又增大了服务器开销。那么,有没有什么能够即不造成用户敏感信息泄露同时又能减轻服务器负担呢?
Token 就是这样一种技术。
说是一种技术,其实更是一种思想,它的操作步骤是上面第一种方式基于数学方式的改良:
- 用户未登陆时,发送认证ID(身份标识)和密码等敏感信息进行登陆;如果登陆成功,服务器根据身份标识和服务器私钥计算Token并返回(计算的方法下面会提到),客户端保留这个Token;
- 登陆后的用户每次发送请求时都带上这个Token以及自己的身份标识,显然身份标识和Token并不是敏感数据(Token一般具有时效性和经过数字摘要处理,因此不属于敏感数据)。
- 服务器根据身份标识和服务器私钥再计算一次Token,和用户附带的Token进行比较,如果一致,则认为是同一个用户。
- 显然,经过以上步骤,用户的登陆状态就被安全的保存到了客户端,而非挤占服务器空间。
- 但是这种方法也有一个很大的问题:Token泄露。
Token泄露
Token泄露有多种情况,例如骇客通过某些方式获得了服务器的私钥和猜到了数字摘要计算方法,或者直接明文窃取一个已登陆的用户发往服务器的Token,伪装自己是这个用户骗取服务器数据。
- 如果只是泄露私钥(内鬼),骇客不知道数字摘要的计算方法依旧无法模拟出目标用户的Token,因此利用PBKDF2和等摘要算法对摘要的哈希、裁剪,完全可以应对这个问题。
- 而如果是窃取报文偷取Token,只能通过SSL等加密通信进行解决;因此完全基于Token的用户状态认证并不是安全的服务器数据访问方式,需要搭配数据安全层协议才能投入使用。
数字摘要
数字摘要所使用的算法常见的如MD5、SHA256、SHA512等,更有经过哈希散列的HmacMD5等。
这里有基于JAVA的摘要算法封装工具类:
[JAVA]数字摘要算法工具类——(Hamc)MD5/SHA1/SHA256/SHA512/PBKDF2
简单Token管理类实例
代码获取:>此处下载<或直接从下文中复制。
设计结构
两个函数类接口:
接口名 | 接口说明 |
---|---|
TokenPartsInterface | 除了用户发往服务器的身份标识外,Token原值的其它内容,如服务器私钥等 |
TokenGenerateAlgsInterface | 对输入的数据进行数字摘要的计算 |
一个管理类TokenManager
API:
方法名 | 方法说明 |
---|---|
generateToken | 产生一个Token |
authenticateToken | 认证Token是否来自同一个用户 |
addTokenParts | 添加Token原值的组成部分(TokenPartsInterface ) |
setGenerator | 设置数字摘要的产生器(TokenGenerateAlgsInterface) |
注意:
- TokenManager对TokenParts的处理简单以
"身份标识+parts"
的方式处理。如有特殊需要,请重写TokenManager.combineTokenParts()
方法。clipToken- TokenManager对Token的剪裁简单以返回原值的方式处理。如有特殊需要,请重写
TokenManager.clipToken()
方法。- 数字摘要生成器的使用可以参考下文中的代码使用Demo。
完整代码
两个接口:
@FunctionalInterface
public interface TokenPartsInterface {
public String getParts();
}