目标:
经过 登录认证方案的论述 后,我们决定自己研发AppToken方案,来实现登录认证。
AppToken的特性
适用场景:AppToken适用于app,不支持cookie协议的地方。
存储:AppToken在客户端存储,一般使用本地存储( LocalStorage ),也在服务端存储,使用表来存储。
用户信息:AppToken是一个短字符串,其中不包含用户信息存储。计划把用户信息单独使用json来存储在客户端
状态:AppToken有状态
失效:AppToken长期有效,一般是3个月,app登录一次后,3个月内有效。可在服务端控制是否失效,在服务端的表中删除对应的token,客户端的登录就失效了。
续命:客户端每访问服务端一次,就会为AppToken续命,赋予新的有效期。
防盗取:这个没有什么办法,和sessionID一样的。如果有人盗取了你的sessionID,就可顶替你登录系统了。解决:使用https
跨域:AppToken由客户端本地存储( LocalStorage ),请求任何域的http接口都可手工携带jwt。不存在跨域问题。
表结构设计
表名 | user_app_token(会员apptoken表) | |||||
---|---|---|---|---|---|---|
列名 | 数据类型 | 约束条件 | 默认值 | 非空 | 是否索引 | 备注说明 |
t_id |
NUMBER(19) | 主键 |
|
是 | 是 | 主键 |
u_id | NUMBER(19) | 外键 | 是 | 是 | 会员ID | |
token | NVARCHAR2(64) |
|
|
是 |
|
令牌(uuid) |
type | VARCHAR2(4) | 0 | 是 |
业务类型:0用户是前台会员,1用户是后台管理员。 shop有两套用户表,目前只给前台会员开发了app,未给后台管理员开发app |
||
status | char(1) |
|
1 | 是 |
|
是否有效(0无效,1有效),如用户退出或修改了密码,应置为无效 |
create_date |
date |
|
sysdate |
是 |
|
创建时间 |
valid_date | date |
|
sysdate | 是 |
|
有效期的开始时间,如2019-01-01。 如果有效期是90天,那么将于2019-03-01的前一秒到期,由定时任务清理。 当为AppToken续命时, valid _date值被更新. |
时序图
服务端返回的数据
app登录成功后,从服务端返回两样东西:AppToken和用户信息json数据, 要存储 在客户端存储,一般使用本地存储( LocalStorage )。
返回的数据json格式请看文档: AppToken方式调用登录接口
用户信息json数据包含以下信息
- 用户名
- 用户头像
- 用户id
- 是否是 采购商
注意-防大量创建session消耗内存
咱使用了AppToken,就不需要使用cookie 和session了。但你如何控制服务端不创建session?
每次客户端调用http接口都会创建session吗?连续访问1万次就创建1万个session,会把内存耗光吗?
答:
servlet:
当客户端访问一个servlet时,默认是不创建session的。
只有你调用了request.getSession()方法 或 getSession(boolean create) 时才会创建。
jsp:
当客户端访问一个jsp页面,默认是自动创建session的。
如果想不创建请在jsp顶部加入以下内容:
<%@ page session="false" %>
总结:不要调用 getSession()方法,就不会创建session,就不会把内存耗光。
为什么叫AppToken
app端的token叫AppToken,这是因为token这个名称已经被占用。
目前系统已有的token
|
已有的token | 说明 | 生命周期 | 工具类 | 存储在哪里 |
---|---|---|---|---|---|
1 | 通用token | 目前用于上传图片和用户激活邮箱 | 一个token只能使用(验证)一次,就作废了 | TokenUtils负责生成token验证token | 在服务端是存在表里 |
2 | AccessKey | 目前用于访问安全图片时要携带AccessKey |
AccessKey的有效期是30分钟,过期后将失效。一个AccessKey在有效期内,可被反复使用。 AccessKey是一个加密的字符串,可从中解密出时间有效期。 |
由com.sicheng.common.fileStorage.AccessKey类负责生成AccessKey、验证AccessKey是否合格 | 无需要存储,AccessKey是一个加密的字符串,可从中解密出时间有效期。 |
所在为app专用的token就叫AppToken了。
|
新的token | 说明 | 生命周期 | 工具类 | 存储在哪里 |
---|---|---|---|---|---|
3 | AppToken | 用于app端用户登录后的身份标识 | 3个月,可续命 |
|
在客户端存储在本地存储中( LocalStorage ),在服务端是存在表里 |
AppToken的缓存设计
AppToken是存储在数据库表中,每次验证都要查数据库,显得重了些,所以可通过缓存技术来提高性能。
三层存储
1、Request,在一次request请求生命范围内缓存数据;
2、Cache,一般缓存N天,使用Ehcache或Redis实现;
3、数据库,持久存储,有续命与定时清理程序来维护;
当要验证某个AppToken是否合法的过程
1、先尝试从Request中取出UserMain,若没找到则走第二步;
2、再尝试从Cache中取出UserMain,若没找到则走第三步;
3、最后从数据库中取出UserMain用户信息,,若没找到就是非法AppToken;
本缓存的不足
1、当使用合法AppToken时,命中缓存的机率较高;
2、当使用非法AppToken时,会穿透缓存直达数据库,缓存的机率为0; 解决思路:AppToken字符串不再使用uuid,使用能加解密或验签名的字符串,先验证合法性再查数据库。(留作以后升级实现)
定时任务–清理过期的AppToken
com.sicheng.admin.task.utils.TaskJob
使用Ehcache缓存带来的无法跨系统的问题
1、wap系统的appToken缓存的Ehcache中,admin系统的定任务无法清理wap系统的缓存
2、seller系统的shior缓存,当admin系统中操作“权限管理”、“菜单管理”时,无法跨系统清理seller系统缓存。
清理apptoken缓存的定时任务入在admin,无法跨系统清理Wap系统的Ehcache缓存
在wap放一套task定时任务模块,是无法实现的, 因为TaskRunnable依赖sysTimedTaskService
解决:Ehcache缓存中的apptoken设置有效期90天,与库中同时到期。缓存到期自动失效。定时任务只清理apptoken表的过期记录。
AppToken的续命
com.sicheng.wap.utils.AppTokenUtils.touchAppToken() 方法可实现续命。
使用了异步线程池。