jwt身份验证

  http协议是无状态协议,服务端不能从请求中判断用户的身份,用户怎么每次去找到本身对应的信息呢?html

  1. cookienginx

  这种方式最简单,在用户第一次登录成功某个网站A,网站A服务端就将你的用户信息(好比用户名,用户id,证件号等等)写入到cookie 对象中,而后再把这个cookie对象发送给对应的客户端,客户端就存下这个cookie,例如博客园的cookie以下redis

 

  当cookie超时时间到了浏览器就会自动删除这个cookie,这个时候须要你从新登陆一下, 而后服务器就会根据你的用户名和密码去数据库中查询一次,成功查询到就再一次将用户信息丢到cookie对象中,返回给客户端存起来,后续每次请求都带着这个cookie算法

  这种方式的好处就是:用户的全部信息都存在客户端,服务端只有在数据库中存了一份,服务端压力很小;数据库

  坏处是显而易见,每次都要带上这个cookie这么多信息,一方面是传输效率问题,另外一方面是安全问题,别人只要截获你的cookie,你的全部信息都尽收眼底;后端

  还有一点就是有的客户端会禁用cookie...浏览器

 

  2. sessiontomcat

  在cookie的基础上优化了一下,由于不是有安全和效率问题吗,那么咱们就把用户全部的信息都存到服务端,例如如今有这样的一个结构:Map<sessionId,Session<User>>安全

  用户第一次登录成功,就会生成一个惟一字符串sessionId,而后将sessionId和用户信息存到map中,最后就将这个sessionId丢到cookie返回给客户端,后续的客户端访问服务端只须要带着cookie,服务端就能从cookie中获取到这个sessionId,到Map里面去找,就能够找到用户信息了;服务器

  注意,不必定非要叫作sessionId这个名字啊,叫作aId,bId等等也行....看每一个地方的要求

  这种方式比较安全,并且效率也提升了,由于只须要多传一个字符串,可是服务端内存中存全部的用户信息,压力都给到了服务端

  咱们还从请求方式来比较cookie和session:

    cookie的方式通常只能用户post请求,由于get请求的url有长度限制

    session的方式只是get和post方式,get方式的话在url后面添加一个参数传sessionId就好了,即便客户端禁用了cookie,在服务端将sessionId传给了客户端以后,客户端想办法存起来下次请求的时候带过去就好了

 

  3. session共享

  上面说的是单体应用的实现方式,可是到了分布式环境下就会失效(不少东西在单机中使用是能够的,分布式环境下就没用了,好比数据库事务,锁),下图所示,会致使tomcat2须要用户从新登陆

 

  解决方案有两种:

    1)hash一致性:在nginx中配置ip_hash,其实就是用过必定的算法对用户的ip处理,假如用户第一次访问的是tomcat1,那么只要用户ip不会变化,第二次该用户访问的仍是tomcat1

    2)引入中间件:这里以redis为例

 

4. jwt

  上面的实现方式看着一大堆东西也是麻烦,又是传sessionId,又是引入redis,在分布式环境下有没有简单的方式啊!

  jwt全称JSON Web Token,咱们以前每次都是传的sessionId,这个字符串是没有实际意义的,只是起到了一个惟一标识的做用,那么有没有可能咱们把它的语义化呢?就是想办法直接解析这个字符串,而后能够获取用户信息

  下图所示,结构是否是一会儿简单多了,能够看到只要咱们每次请求都带上这个token,不论是单机环境,仍是分布式环境都适用,并且服务端也不须要保存什么东西,客户端只须要保存一个token字符串就好了;

 

  如今就比较关心的是jwt的那个算法和生成后的token字符串有什么特殊的要求!

  token字符串的格式,分为三部分,用点进行链接:aaa.bbb.ccc

示例:

 

  第一部分是Header:放入token的类型(“JWT”)和算法名称(好比:HMAC SHA256或者RSA等等),而后使用Base64对这个JSON编码就获得JWT的第一部分

 

  第二部分是Payload:通常放入用户的不敏感信息,好比用户id,名称和角色等,即便被别人截获了也没啥用,而后使用Base64对这个JSON编码就获得JWT的第二部分

 

  第三部分是Signature:准备一个只有你本身知道的密钥,加上第一部分的字符串aaa和第二部分的字符串,经过Header中声明的算法就生成了签名,也就获得了第三部分

 

  将上面三部分经过点相连就组成了token,而后发到客户端,客户端只须要每次在请求头中放入这个token,后端经过密钥验证这个token的合法性,而且从Payload中获取用户不敏感的信息,进行后续处理

  想看看简单的demo,能够看看这个老哥的博客 ,不过通常校验jwt是配置一个拦截器进行处理的

 

5. jwt的补充

  其实仔细想了想,通常还有如下两个疑问

  1)Token被盗了怎么办?

      答: 在启用https的状况下,token被放在Header中仍是比较安全的。另外Token的有效期不要设置过长。例如能够设置为1小时(微信公众号的网页开发的Token有效期为2小时)。

      2)Token到期了如何处理?

     答:理论上Token过时应该是跳到登陆界面,但这样太不友好了。能够在后台根据Token的过时时间按期去请求新的Token。

能够看看如下两篇博客看看

应用JWT进行用户认证及Token的刷新

JWT生成token及过时处理方案