最近和群里网友聊天,发现他在数据接口中校验登陆状态用的仍是session,在我及时劝说和科普以后,他最终决定改用JWT。那么接下来咱们就聊一聊数据接口应该怎么管理登陆状态以及什么是JWT前端
先后端混合开发的时候,用户登陆状态的管理通常都是经过session来实现的,原理很简单:用户登陆后,服务端将登陆用户信息存储到服务器上的特定位置,并生成对应的session id存储到浏览器的cookie中。须要校验的时候先读取cookie中的session id,找到服务器中对应的存储内容,完成校验。
很显然,这个机制是创建在cookie基础上的,cookie又依赖于浏览器,并且有域名限制。是不适合app、小程序、以及先后端时数据接口采用其余域名等状况的。算法
app、小程序、先后端分离时的数据接口通常采用token来作登陆信息校验。原理是用户登陆后,服务端生成对应用户的一个token(通常都是一段无心义的惟一字符串)后返回,app、小程序、前端(如下统称为前端)拿到token后保存,在须要校验用户登陆的接口请求中加入token(能够是get、post参数或者http header的形式),服务端拿到token后校验真实性、有效性等信息后完成登陆校验。通常为了防止盗用,还会设置一套签名校验的过程。
其实token和session的原理是差很少的,都是服务端将对应用户的一个key(session的时候是session id,token的时候就是token)交给前端,前端经过token请求服务端,服务端再去反查用户,获取用户登陆状态。
如今通常微信、微博等接口都是采用的这种方式。可是这种方式也有弊端,主要是:json
这时候,就轮到咱们此次的主角JWT出场了。小程序
JWT是JSON Web Token的简称,有官网详细介绍,你们能够看一看,这里简单说一下。
JWT其实就是一种特殊的token,原理和使用方法天然和token同样。
JWT是由三部分组成的字符串,结构是:头部+主体内容(官方称之为Payload)+签名,三部分用“.”链接。头部和主体内容都是json格式的字符串再通过base64编码,为了方便放在get请求中,还须要把相似“=”、“/”等特殊字符替换掉。后端
头部内容是固定的,原始json就是下面这样数组
{ "alg": "HS256", "typ": "JWT" }
主要是说明了最后签名部分的加密算法。浏览器
重点是中间的主体内容,原始json通常是相似下面这样的安全
{ "user": "John Doe", "exp": "2020-01-01 12:24:30" }
主体内容一个是当前登陆的用户,能够是用户id,也能够是用户名等能够检索定位到用户的信息;还有一个就是过时时间。还能够加入一些其余不私密的信息。
服务端拿到JWT以后能够在不读取数据的状况下,仅经过解码这部分信息就能够完成获取登陆用户以及判断是否过时等初期工做。服务器
最后的签名通常是把头部、主体内容再加上secret拼接成字符串再加密,这一步在用户登陆生成JWT的时候就完成了。服务端拿到JWT以后只须要把前两部分加上secret再计算一次签名加以比对就能够完成校验签名,前端不须要同时保存secret。微信
JWT官网提供了各类服务端语言的生成代码,这里我提供一个我本身用PHP写的相对简化的方法,供你们参考
private function _jwt($payload){ $header['alg']='HS256'; $header['typ']='JWT'; $jwt_header=$this->_base64url($header); $jwt_payload=$this->_base64url($payload); $jwt_sign=hash_hmac('sha256', $jwt_header.'.'.$jwt_payload, $this->secret); $jwt['token']=$jwt_header.'.'.$jwt_payload.'.'.$jwt_sign; $jwt['sign']=$jwt_sign; return $jwt; } private function _base64url($a){ $c=base64_encode(json_encode($a)); $c=str_replace('=', '', $c); $c=str_replace('+', '-', $c); $c=str_replace('/', '_', $c); return $c; }
我这个方法里须要把主题内容以数组形式的参数传入,最终返回了生成的JWT和签名,方便接收时校验签名。
JWT在实际使用中也是存在问题的,目前想到如下几点: