jwt身份验证

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

  1. cookie

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

 

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

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

  坏处是显而易见,每次都要带上这个cookie这么多信息,一方面是传输效率问题,另一方面是安全问题,别人只要截获你的cookie,你的所有信息都一览无余;

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

 

  2. session

  在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及过期处理方案

 

posted @ 2021-02-20 16:47  java小新人  阅读(557)  评论(0编辑  收藏  举报