zion项目启动
在过去一年中,我投入时间和精力相对较多的一件事,便是研究了openresty并学习了一点Lua语言。虽然都并不深入,但基于这两者,在工作的过程中还是写了一些脚本,比如构建公司账户系统的token机制,还有其他一些关于日志收集,限流等功能。总觉得还不够,openresty是一个性能非常高的平台,我觉得应该把更多的任务交由它来运行。但是现在知道或者应用它的人还非常少,所以决定写一个项目。
我并没有什么好的规划,这个项目也只是一时兴起,所以功能可能会比较杂。但是我保证,那些功能绝对在实际运用中是非常急需的,非常有价值的。
功能
在项目开始之前,我要简单的规划一下项目的一些规范,要具备的功能等,为以后的开发指明一个基本方向。
规范
命名规范
- 文件命名:小写字母 + 下划线_
- 变量名函数名:小驼峰命名法
- 全局常量: __开头全大写
接口规范
请求: 使用restful风格GET:查询, POST: 新建 PUT: 更新, DELETE: 删除
响应: 一律响应json串
具体功能
- 日志收集(kafka) / log_collection
- token
- 限流
- 异常IP,请求头检测及封锁
- OAuth2 (待定)
- 动态摘挂机器
token认证机制
在微服务盛行的当下,服务被拆分成多个微服务,它们可能不仅仅是在后端分拆成不同的web服务,甚至可能在不同的域名下,传统的session认证方式已经无法满足业务的需要,因此才需要token这种无状态的认证方式。
token可以翻译成令牌,他的概念很好理解,也就是说,客户端在向服务气短请求数据时,必须要要带着一张令牌,服务器端在验证令牌合法后,才会返回数据。
JWT
JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快 **自包含(Self-contained)**:负载中包含了所有用户所需要的信息,避免了多次查询数据库。
JWT结构
JWT包含了使用.分隔的三部分: header.payload.signature
header
header种通常包含两部分。token的类型和采用的加密算法:
1 | { |
然后使用base64编码该json字符串得到header。
PayLoad
Token的第二部分是负载也可以叫消息体。它包含了一些标准的字段,同时也可以自定义添加字段。
1 | { |
将上述json进行base64编码得到payload.
Signature
得到header和payload之后,将header.payload字符串按照header种定义的加密算法进行加密,得到加密字符串signature. 其中加密所用的secret存储在服务器上,在校验token有效性时使用同样的secret进行校验。
token
最后连接header.payload.signature得到token. 这个操作是在服务器上进行。生成token后返回给客户端,客户端在进行请求时,带着token, 服务器端进行token有效性检查。
jwt优缺点
优点
- jwt是无状态的,token保存在客户端,服务器端不需要保存,节省服务端开销
- jwt种保存了用于校验的信息,服务端不需要查询数据库,性能好
缺点
- 由于服务器端不保存token状态,无法做到立即强制失效。这一点很蛋疼。
- payload种需要添加可唯一标识用户的信息,而且base64等同于明文
jwt改进
我们把改进的重点放在强制失效上,因为在实际的应用中,这实在是一个刚性需求。那么怎么才能做到呢?我想了很久,好像除了在服务器上保存token的状态之外,别无他法。那么怎么来标识用户当前token是否。我们在服务器端校验有效性时,是使用存储在服务器端的密钥来校验,如果我们修改了这个密钥,那token不就立即失效了吗。所以解决的办法就是,我们在服务器端对每一个用户都保存一个对应的密钥。不同的用户请求使用对应的密钥来进行校验,这样还有一个好处,就是即使密钥泄露,可能也只影响一个用户,安全性更高。
要实现的功能
本次我不打算实现太多的功能,但是会极可能的考虑可扩展性。
实现原则:jwt中存放尽量多的信息,而服务器端存放尽可能少的信息。
进度
7/14 加密算法已经搞定.
密钥存储方式
tkutil.lua