咱们在设计构建一个系统的时候,权限管理和用户认证是最基本功能,其中关于用户认证这块是一个比较常见的模块。在已有的方案中,咱们最多见的就是保存到 tomcat 中的 session 对象中。随着微服务的兴起,一种新的认证方法又火了起来,那就是JWT,下面我就浅析下本身对两种认证方式的认识,一些经验和你们探讨。web
我对认证的理解就是,当一个设备(客户端)向一个设备(服务端)发送请求的时候,服务端如何判断这个客户端是谁。传统意义有两种认证方式:有状态认证、无状态认证。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。面试
有状态的认证,以 cookie - session 模型为例,当客户端第一次请求服务端时候,服务端会返回客户端一个惟一标识(默认在cookie中),并保存对应的客户端信息。客户端接受到惟一标识以后,将标识位保存到本地cookie中,之后的每次请求都携带此 cookie ,服务端根据此 cookie 标识能够判断请求的用户是谁,而后查到对应用户的信息,大概示意图以下:redis
一、客户端向服务端发起请求;算法
二、第一次客户端发起请求,服务端建立一个 key 为JSESSIONID
的值,并写入到客户端的cookie中,同时在服务端的Session Manager中建立一个对象,保存这个 JSESSIONID 对应的信息;spring
三、之后客户端每次请求,都会根据cookie进行区别,咱们能够经过 session.setAttrbutie,session.getAttrbuite 等方法,拓展用户信息,根据用户信息作一些业务判断等;数据库
四、Session Manger 中维护有一个定时器,当 JSESSIONID 对应的信息长时间没有访问(默认30分钟),或者显性调用 session.invalidate 方法,那么这个对应的信息将会被删除。跨域
那么针对有状态的认证,咱们分析下他的利弊:浏览器
由于客户端的信息都保存在服务端的 Session Manager 中,若是要将客户端的认证信息取消,只须要将对应的session 信息删除便可,及时响应,方便快捷。缓存
一、由于服务端保存着客户端的信息,当用户量特别多时候,服务端须要特别的内存资源;tomcat
二、若是失效时间特别长的状况下,大量资源被占用没法释放,若是释放,那么至关于用户的注销登陆;
三、客户端的信息在服务端中维护,若是服务端为集群的场景下,那么客户端信息不共享,必须使用分布式 session 或者其余方案;
四、cookie有同源策略和跨域限制,部分业务场景下cookie并不能传递;
五、部分设备自己不支持cookie或者禁用cookie,还有的手机浏览器也不支持cookie。
一、若是公司以集群式部署多台服务,那么能够采用的策略有:配置负载均衡的路由策略为hash一致算法(不推荐),若是某个机器停机,那么会从新分配到新机器,又须要从新登陆;session复制方式(不推荐),复杂度太高;分布式 session 方案(强力推荐),目前市场上有 spring-session 的依赖,能够将 session 保存的容器从应用内部抽取到 redis 或者 数据库中供多个应用使用,实现集中管理,为了保证设备的兼容性,spring-session提供了将认证方式从cookie修改成header,web网站能够保存到 SessionStorage,移动端能够保存到本地缓存中。
二、若是一个公司有多个产品须要共享认证信息,此时须要使用 SSO Server。
无状态的认证,客户端在提交身份信息,服务端验证身份后,根据必定的算法生成一个 token 令牌返回给客户端,以后每次请求服务端,客户端都须要携带此令牌,服务端接受到令牌以后进行校验,校验经过后,提取令牌中的信息用来区别用户,大概的示例图以下:
一、执行登陆操做,用户端发送帐号密码等信息;
二、服务端校验帐号密码是否正确,若是正确,根据对应的用户信息和服务端秘钥生成 JWT 令牌,而后经过response.setHeader 返回给客户端(此处假设生成了一个名为 x-auth-token 的令牌);
三、客户端在返回成功以后,将Header中的x-auth-token
保存到本地的LocalStorage中;
四、客户端在之后每次请求服务端时候,都在header中携带x-auth-token
令牌的值;
五、服务端每接受到请求以后,判断hader中是否包含x-auth-token
,token 是否有效,而后经过 BASE 64 算法 decode,根据解密后的参数,判断当前 token 是否在有效期,所访问的接口是否有权限等操做。
一、由于服务端不保留客户端的任何信息,每次只须要经过特定的算法进行校验,节省了大量存储空间;
二、方便水平扩容,不须要 SSO Server,只要保证新的应用采用一样的验证算法,就能够验证经过并得到对应信息。
当客户端的token被盗用,或者须要手动封禁某个用户的时候,没办法对此token进行操做,必须等待token失效(若是在服务端维护token和用户的关系,技术能够实现,可是违背无状态的设计理念)。
一、生成的 token 中携带用户经常使用信息,可是不携带用户的敏感信息,好比密码手机号等等,由于这些信息经过BASE 64 能够解密出来的;
二、要处理服务端主动禁用某个 token ,能够采用黑名单措施,每次请求前判断当前token是否已经被禁用;
三、token 中的信息除了基本信息外,还应该携带好比签发时间、有效时间、刷新token等字段,用来处理token的续约问题。
在实际的项目中,咱们该如何选择认证模式,是有状态的认证仍是无状态的认证呢?之前看文章时候,在掘金中看到有人把 JWT 批评的一无可取,就和垃圾同样。我我的以为吧技术没有谁好谁坏,谁旧谁新,也没有谁该被时代淘汰,存在及合理,咱们须要充分理解需求,合理使用技术,只有最合适的技术才是最好的选择。 下面是我关于技术选型时候的一些我的观点,但愿你们批评指正和交流。
在个人经验中,目前比较流行的就是互联网APP中大部分采用 JWT 的认证方式,一些企业内部管理系统则大部分采用 cookie-session 的机制,大量的商业案例下,我我的分析推测的缘由可能以下:
一、在互联网APP产品中,尤为以 to C 模式,用户量极大,为了用户体验,通常会将登陆信息保留特别长时间,某些APP 只要你不卸载,那么无论几个月以后登陆,帐户仍是处于登陆状态。在这种状况下,假如采用 cookie-session 机制,那么你的用户信息保存不少个月,用户量特别大的状况下,会形成大量资源占用和浪费,这种场景采用 JWT 就是相对比较好的方案。
二、企业内部管理系统有如下特色:用户量较少(最多最多不超过10W人),信息安全要求高(及时踢出客户端登陆状态,我的浏览器关闭帐号退出登陆),在这样的场景下占用的内存不会太多,因此基于 cookie-session 这种机制,是比较好的方案,若是企业内部还有其余应用须要集成时候,须要使用 SSO Server 实现。
最近在找工做,若是闲下来有时间的时候会写两个项目出来,敬请期待:
一、 spring security + JWT 的验证案例
二、shiro + spring-session (header替换cookie)的验证方案
ps:蚂蚁5面技术过了,期待hr面试的早点到来,给本身加油。