会话
服务器的存储:
- request:只作用于一次请求中,请求结束,该request就失效
- session:局部变量,用户浏览器级变量,浏览器打开就一直有效,每个用户都有一个sessionID;session保存在服务器中
- servletContext:全局变量,代表web应用得上下文,只要服务器没重启就一直保存着
cookie:Cookie是由服务器端生成,发送给User-Agent,浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器;是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。
token:是由服务器生成的加密字符串,一般用于登录状态的记录
token和cookie的区别?
cookie:举例:服务员看你的身份证,给你一个编号,以后,进行任何操作,都出示编号后服务员去看查你是谁。
token:举例:直接给服务员看自己身份证
会话就是用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。会话就是系统为了保持当前 用户的登录状态所提供的机制,常见的有基于session方式、基于token方式等。
基于session方式
当用户登录成功时,将用户唯一id或用户名保存在session中;然后把session_id发给客户端,客户端每次请求时都带上session_id,根据这个id去查询是否存在用户信息,不存在则重定向到登录页面
根据上面的工作流程,基于session方式时需要解决以下几个问题:
- 如何验证用户是否登录?
- 如何实现用户信息的过期?
- 如何刷新session?
- 当用户数量巨大时,服务器压力大,如何解决?
问题一:如何验证用户是否登录?
将用户信息存入session中,session_id作为键值,传给前端,前端每一次请求都需要带上,看是否能取出用户信息
问题二:如何实现用户信息的过期?
在将用户信息保存在session时,可以设置该session的有效期,到时间会自动删除;
但是,存在一种情况,当用户正在使用网页时,session失效,就必须重新登录,体验极差
问题三:如何刷新session?
再每次对用户进行校验时,校验成功,就刷新一次session,删除原来的,再重新设置
问题四:当用户数量巨大时,服务器压力大,如何解决?
当用户量巨大时,服务器的压力就会很大,需要保存成千上万用户的session_id,这对服务器来说是一个巨大的开销,严重限制了服务器的扩展能力,当服务作为一个集群被部署时,那么怎么做到一个服务保存的session_id,可以被其他服务公用呢?解决办法就是session的赋值,把session_id在几个机器间搬来搬去;也可将session_id集中在一起,即行成会话session验证的服务,但是增加了单点失败的可能性,且负责session的机器挂了,所有人又得重新登录。
基于token方式
token的基本流程
token是一种身份验证的机制,为了解决http的无状态,避免用户重复登录系统;首先,在初始时,用户提交账号数据到服务器,服务端在校验密码无误后,采用一定策略生成一个字符串(token),token字符串中含有用户少量的信息,并且该字符串有一定的期限,服务端会把token字符串传给客户端,在后面的每一次请求中带上这个字符串。
在上面的工作流程中,我们需要解决以下几个问题:
- 服务端如何根据token获取用户信息?
- 如何保证token不是伪造的,即不是服务端生成的?
- 如何应付冒充的token,即请求被拦截后,使用该token冒充合法客户端去请求?
- 如何实现token的刷新?
第一个问题:服务端如何根据token获取用户信息?
在token字符串中,可以存储用户的id,服务端在接收到token后,可以根据用户id去获取到用户数据,从而将token和用户关联上
第二个问题:如何保证token不是伪造的,即不是服务端生成的?
一般情况,在token中只存放不敏感的数据,然后将数据用私钥进行加密,将加密后的结果与数据进行组合构成token,发送给客户端,校验token时,将加密后的数据用私钥解密,与前面的数据进行对比,看是否相同;注意,私钥不能泄露。比如JWT的实现。
其实这里主要的点就是做到无法伪造token,用加密即可实现,如,对用户id和登录时间进行加密,如果解析出来的数据里有这两个数据,则就说明是正确的;不一定非要使用jwt,jwt只是一种规范,能在数据交流中更加的方便。
第三个问题:如何应付冒充的token?
给token加上有效期;可以在token中加入用户登录的时间和token的过期时间,每次校验时,判断用户id是否正确,判断该token是否过期;
第四个问题:如何实现token的刷新?
第一种:服务器缓存token及对应的过期时间,校验成功,就重新设置过期时间;该方法也需要在服务器保存信息,和session没什么两样
第二种:token中含有过期时间,由客户端进行校验token的有效时间,客户端发现快过期了,将原来的token带上请求刷新token的接口,判断原来的token是否过期,无则重新生成一个token
用户在认证完成后,服务端会生成一个token令牌返回给浏览器,浏览器可存储在cookie或本地localStorage等存储中,每次请求时都带上token,服务端接收后,解析校验令牌,并获取当前用户数据,在token中加入时间戳,有效时间过了或退出,需要重新进行认证。
基于jwt实现过程
1.登录成功生成token
token策略:,并且用户的用户名,当前的登录时间,token的过期时间
用户的用户名,当前的登录时间,token的过期时间
2.访问服务器,带上token
3.校验token
从Header中取出token
从token中获取登录用户名
判断用户名是否存在
根据用户名获取用户信息和用户权限
验证token是否有效,传入token和查出的用户信息
策略:
取出token中的用户名,判断用户名和数据库查出的用户名是否一致,并且通过token的过期是时间判断是否已过期
失效,返回给前端要求重新登录
5.动态刷新token
实现目标
- 延长
token
过期时间 - 活跃用户在
token
过期时,在用户无感知的情况下动态刷新token
,做到一直在线状态 - 不活跃用户在
token
过期时,直接定向到登录页
前端检测到token
过期后,携带refreshJwt
访问后台刷新token
的接口,服务端在拦截器中依然对refreshJwt
进行解析鉴权
- 假如
refreshJwt
也过期了,提示登录过期,强制跳转登录页 - 假如
refreshJwt
还在有效期,则签发新的token
返回,前端使用最新的token
进行接口请求
session和token的区别
基于session的认证方式由Servlet规范定制,服务端要存储session信息需要占用内存资源,客户端需要支持 cookie;基于token的方式则一般不需要服务端存储token,并且不限制客户端的存储方式。如今移动互联网时代 更多类型的客户端需要接入系统,系统多是采用前后端分离的架构进行实现,所以基于token的方式更适合。