web认证机制

引言

之前对认证这方面的认识一直不太深入,不清楚为何须要token这种认证,为何不简单使用session存储用户登陆信息等。最近读了几篇大牛的博客才对认证机制方面有了进一步了解。前端

  • Basic Auth

这种认证直接顺应HTTP协议的无状态性,每次执行业务的时候,都暴力地附带username与password参数,并将其发送给服务器进行验证。尽管在服务器端能够优雅地使用AOP技术(如拦截器或动态代理)对全部controller进行前置的登陆验证。但若是每次验证都要查数据库的话,建立链接与查询操做势必会增大开销。若是服务器端不作任何记忆(有状态性)处理的话,那么这种方式就已经没有其余办法能够优化了。算法

  • Cookie/Session Auth

上面已经点到,只要服务器端稍加一些记忆处理(记录哪些用户登陆过)便可大大优化这个过程:只须要在用户第一次登陆系统的时候,将对应的username放入一个相似与Set<String>的数据结构中。只要登陆一次(保证不退出),那么当用户第二次访问controller的时候,只须要查询Set<String>中是否有该username便可。但这种方式仍有不足,即每次仍是必需要求客户端传username过来,不然服务器端不知道是谁就没法判断了。
要优雅地解决上述问题,就要得益于后来HTTP协议中出现的Cookie与Session技术了。当浏览器利用HTTP协议访问服务器的时候,服务器会为其自动建立一个其独有的session对象。session在基本的数据结构上相似于键值对Map,但不一样的是它还提供了若干操做方法,且能够设置时效。既然一个浏览器惟一对应了一个session,那就好办了,用户第一次登陆验证成功后,就可把用户名写入session中表征当前处于该浏览器上的用户已经登陆,之后访问controller只用查session中是否有username键便可,如有放行,若没有则阻止。以下图所示:spring

  • Token Auth

目前被众多公司普遍采用的是token认证,它的认证过程都是围绕着一个名为token字符串展开的,其认证流程以下:数据库

第一次登陆
用户携带username与password请求第一次登陆(为保证安全性一般采用HTTPS协议传输);
服务器接收到后,查询数据库看用户是否存在且密码(MD5加密后)是否匹配,若匹配,则在用户表中查询该用户信息(角色、权限、状态等);
从配置文件中读取签名的私钥,并整合上一步获得的用户信息生成token(可采用第三方库JWT lib);
将token写入cookie并重定向到前端。
登陆后访问业务
用户携带从cookie(若为移动终端,能够是数据库或文件系统)取出的token访问需登陆及特定权限的业务;
请求首先被认证拦截器拦截,并获取到传来的token值;
根据配置文件中的签名私钥,结合JWT lib进行解密与解码;
验证签名是否正确(若不正确JWT会抛出异常)、token是否过时与接收方是不是本身(由本身判断)等。若经过则证实用户已登陆,进入权限验证阶段;
经过权限验证框架(shiro、spring security等)验证用户是否具备访问该业务的权限,如有则返回相应数据。浏览器

认证方式比较

1.cookie支持问题
session和cookie实际上是紧密相联的。浏览器与服务器首次创建链接的时候,服务器会自动生成一个会话号sid,并写入响应报文的首部字段<Set-cookie>中,返回给客户端让其存入cookie。以后每次的HTTP请求报文中均会在首部写入cookie中的sid,服务器接收到后根据sid取出对应session,再进一步根据username键是否存在判断登陆与否。
能够看出cookie/session认证要求客户端必须支持cookie技术,但很显然,客户端并非只能为浏览器,还能够是PC桌面、移动终端等其它平台,对于这些平台,咱们没法保证他们都能支持cookie技术。而token认证只认token这个字符串值,至于前端是浏览器采用cookie存的token仍是Android终端用数据库存的token都无所谓,只要拿到token值便可进行验证。
2.session共享问题
session是没法在多台服务器之间共享的,特别在分布式部署环境(即多台部署了同一系统的Web服务器集群)下将带来不少同步、一致性问题。好比下面这个场景:
用户请求登陆,HTTP请求被转发到了服务器A,在A上完成认证后将登陆状态记录到了session;
用户后续请求其余需登陆的业务,HTTP请求被转发到了非A的服务器上,这时因为这些服务器上的session并不是A上的session,因此其上就没有登陆状态记录,因此业务操做将被拒绝!
很显然这时采用cookie/session认证就很棘手了,须要本身去维护同步、状态一致等问题。而token根本不会依赖session,全部服务器都是一致地采用私钥+解密算法分析签名的正确性。
3 时间/空间开销问题
若是session不只是要存储用户名,还要存储时效时间、登陆时间等各类状态信息(特别是大型系统),那么一旦登陆的用户数激增,服务器的内存消耗也将急剧增大。而token认证是彻底将状态存入了token值中,再利用加解密算法将状态取出,用时间复杂度换取了空间复杂度,内存开销大大减少,时间效率有下降。
4 第三方受权问题
采用传统认证方式,若要访问业务,必定要先登陆。假如这时一个第三方应用但愿获取该用户在本系统的一些资源(如头像、昵称、签名等),则必定要先接受登陆拦截器认证才可放行,这时若是第三方应用也经过用户名+密码登陆的形式来获取信息的话,势必会暴露用户在本系统的信息,很不安全!
而一种更巧妙的作法是,先记录第三方应用的AppID与其url地址,而后跳转到本系统登陆页面进行登陆,认证成功后,经本系统的认证服务器生成access_token,携带该参数并重定向到url地址所在页面。此后第三方应用便可凭借该access_token的权限范围,访问所需的本系统的资源。
能够看出,不管是本系统本身凭借token访问本身的资源,仍是第三方应用凭借access_token访问本系统资源,依靠的都是token这个凭据,走的都是统一的一套流程,而传统方式,须要额外写一套,可维护性很很差。关于第三方认证文章能够参考理解Ouath2.0。安全

结语

虽然token认证优点很是明显,但仍然须要考虑以下问题:如何抵御跨站脚本攻击(XSS)、如何防范重放攻击(Replay Attacks)、如何防范MITM (Man-In-The-Middle)攻击等。对此本文就再也不作详细叙述了。服务器

相关文章
相关标签/搜索