http协议是无状态的所以需用通过一些方法实现"会话"(session)。
实现会话的第一步是登陆,登陆后系统就能给该账号颁发"唯一码"。
cookie
最早也是最普通的一种实现会话是通过cookie携带"唯一码"进行鉴别。
该方法简单,通过浏览器cookie机制,后端写在cookie里什么东西,cookie都会原封不动的在请求时候带上。
但是浏览器的这种cookie机制有个前提,必须是同域,即相同的域名、端口、http(s)协议。A站点后端写的cookie,你B站点后端是获取不到的,因为浏览器压根就不会把A站点的cookie信息写道B站点。
所以cookie安全上有好处,但是面对现在的前后端分离开发就要麻烦一点。
token
既然cookie不能进行分离开发,那把唯一码放到一个可以进行跨域访问的地方不就可以了么?
token方法就是把"唯一码"放在浏览器的缓存中,唯一麻烦点的地方是前端,要手动实现每次请求前给header头添加token。而cookie却是自动的。
虽然前端可以跨域了,但是这也带来了安全隐患,如果一个人拿着这个token,那他可以在任何地方冒充你。
解决办法就是定期更换token,需要前后端同时实现一套token过期及token刷新的机制。
要实现这样的机制复杂点在于要考虑并发情况下token的过期处理,比如两个请求流同时进来,碰巧这个两个流中的token都失效了,如何刷新才能保证两个流都可以正常结束。这就要求旧token也要在一定时间段里继续有效,而这些新旧token的有效性都需要后端去处理。这也带来了后端的复杂性。
jwt
jwt自身带有失效机制,后端只用做一个刷新接口即可,前端在每次进入首页或者某个页面的时候进行jwt有效性验证和刷新即可,这样就算并发请求,带着不同的jwt去访问,后端也不会出问题,因为在没有过期之前都是有效的。
另外,jwt最好只用来实现单一"会话"功能,即在jwt中只存储用户Id之类的数据,不要存储其他数据,要实现其他功能比如权限验证,需要在后端设计权限系统,通过jwt中拿到的用户Id再去redis中拿用户权限。
有人说既然要在redis中拿用户信息,那用token方案,把token放在redis中,不是更好么?还是token中提到的哪个问题,后端开发token的失效刷新很复杂。不如直接用jwt简单,所以jwt只管用户鉴别,只存储用户ID,其他的交给鉴别后的系统吧。