JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案。
1. 基于token的认证
当用户成功登录系统并成功验证有效之后,服务器会利用某种机制产生一个token字符串,这个token中可以包含很多信息,例如来源IP,过期时间,用户信息等, 把这个字符串下发给客户端,客户端在之后的每次请求中都携带着这个token,携带方式其实很自由,无论是cookie方式还是其他方式都可以。当服务端收到请求,取出token进行验证(可以验证来源ip,过期时间等信息),如果合法则允许进行操作。
基于token的验证方式它有什么优点吗?
- 支持跨域访问,Cookie是不允许跨域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
- 无状态:Token机制在服务端不需要存储session信息,因为Token自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
- 解耦 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
- 适用性更广:只要是支持http协议的客户端,就可以使用token认证。
- 服务端只需要验证token的安全,不必再去获取登录用户信息,因为用户的登录信息已经在token信息中。
- 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT).
那基于token的认证方式有哪些缺点呢?
- 网络传输的数据量增大:由于token中存储了大量的用户和安全相关的信息,所以比单纯的cookie信息(例如session_id)要大很多,传输过程中需要消耗更多流量,占用更多带宽,
- 和所有的客户端认证方式一样,如果想要在服务端控制token的注销有难度,而且也很难解决客户端的劫持问题。
- 由于token信息在服务端增加了一次验证数据完整性的操作,所以比session的认证方式增加了cpu的开销。
但是整体来看,基于token的认证方式还是比session和cookie方式要有很大优势。在所知的token认证中,jwt是一种优秀的解决方案。
2. jwt认证
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。中间用点(.
)分隔成三个部分。注意JWT 内部是没有换行的。
2.1 头部
header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。
代码语言:javascript复制{ "alg": "HS256", "typ": "JWT"}
2.2 Payload
Payload 部分也是一个JSON对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
代码语言:javascript复制iss (issuer):签发人exp (expiration time):过期时间sub (subject):主题aud (audience):受众nbf (Not Before):生效时间iat (Issued At):签发时间jti (JWT ID):编号
除了以上字段之外,你完全可以添加自己想要的任何字段,这里还是提醒一下,由于jwt的标准,信息是不加密的,所以一些敏感信息最好不要添加到json里面
代码语言:javascript复制{ "Name":"菜菜", "Age":18}
2.3 Signature
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥(这个秘钥只有服务端知道),签名算法是header中指定的那个,然后对它们签名即可。
代码语言:javascript复制HMACSHA256(base64UrlEncode(header) "." base64UrlEncode(payload), secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用”点”(.)分隔,就可以返回给用户。需要提醒一下:base64是一种编码方式,并非加密方式。
3. jwt使用
3.1 流程
- 客户端携带用户的登录凭证(一般为用户名密码)提交请求
- 服务端收到登录请求,验证凭证正确性,如果正确则按照协议规定生成token信息,经过签名并返回给客户端
- 客户端收到token信息,可以保存在cookie或者其他地方,以后每次请求的时候都携带上token信息
- 业务服务器收到请求,验证token的正确性,如果正确则进行下一步操作
3.2 交互
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。 此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。
代码语言:javascript复制Authorization: Bearer <token>fetch('api/user/1', { headers: { 'Authorization': 'Bearer ' token }})
3.3 特点
(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。 (2)JWT 不加密的情况下,不能将秘密数据写入 JWT。 (3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。 (4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。 (5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。 (6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
3.4 问题
- 用户登出,如何设置token无效?
- 用户登出,浏览器端丢弃token
- 使用redis数据库,用户登出,从redis中删除对应的token,请求访问时,需要从redis库中取出对应的token,若没有,则表明已经登出
- 两个不同的设备,一个设备登出,另外一个设备如何处理?
- 服务器维护一个清单(记录该账号是否已经签发token),这样又回到session的老路了
- 每一个设备与用户生成唯一的key,保存在redis中,即设备1的用户登出,只删除对应的token,设备2的token仍然存在
- 服务器端维护一个版本号,相同用户不同设备登入,版本号加1,这样保持key的唯一性(和上面差不多)
source: //www.liuvv.com/p/722ed7e7.html