1.session
session不是在浏览器第一次请求时创建,而是在第一次使用时创建(request.getSession())。
最终创建逻辑在org.apache.catalina.connector.Request的doGetSession()方法中,如下代码可以看到,这里会让请求方设置一个cookie:JSESSIONID
/* org.apache.catalina.connector.Request doGetSession() 部分代码 */
Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie(context, this.session.getIdInternal(), this.isSecure());
this.response.addSessionCookieInternal(cookie);
注意:服务端使用一个ConcurrentHashMap存储session,由于session是存储在应用中的,因此也存在session集群共享问题,为解决session共享问题,可使用spring-session。
2.spring-session
spring-session就是把session的存储从应用中剥离出来单独存储,一般存放在缓存如redis中,这样应用集群都从redis单机或集群中获取session,也就不存在session共享问题了。
使用spring-session的示例
3.token
session的主要作用就是存储用户相关数据,token作用与session类似,个人理解为session的改进版。
token与session对比:
- 客户端sessionId存储在浏览器的cookie中,token可以存储在localStorage、cookie、sessionStorage中。
- 服务端session存储在应用中,token关联的数据则可以存储在应用或者缓存中。如果服务端重启,session失效,token如果在缓存中则仍然有效。
- 如果客户端禁用cookie,session将失效,客户端如果将token保存在非cookie中,则仍然有效。
- token的逻辑需要单独写。
4.JWT
Json web token (JWT),用于作为JSON对象在各方之间安全地传输信息。JWT由三个部分组成:header(头部)、payload(载荷)、signature(签名)。
header
tpy:声明使用JWT,alg:用于生产签名的算法
{
'typ': 'JWT',
'alg': 'HS256'
}
通过base64生成header部分:eyd0eXAnOidKV1QnLCdhbGcnOidIUzI1Nid9
payload
载荷一般存储用户相关信息,由于只进行base64编码,因此不建议存储敏感数据。
以下为默认提供的字段,除此以外,可以使用自定义的字段如用户名、昵称等。
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
再构建完后同样需要进行base64编码生成payload部分。
signature
通过header、payload部分,再使用header中声明的算法,结合盐,最后通过base64编码生成signature部分。
三部分使用 . 相连构成了最终的JWT——header.payload.signature。
缺点分析:
- 由于用户相关数据从服务端转移到客户端JWT中的payload中,并且会随每次请求携带,可以理解为每次请求都会带一些无用的数据,因此不建议payload存储过多的数据。
- 修改payload中的数据时需要重新构造JWT,因此如果payload中的数据修改较为频繁,建议使用session或token。
- JWT过期时间不支持动态刷新,并且在有效期间JWT将一直生效,不能取消。
适用场景:
- 一次性验证:如邮箱激活,好处是服务端不用保存激活相关的数据,都放到JWT的payload中了。
- 接口鉴权:即作为请求端有权访问服务端的标识。