目前我们常用的鉴权有四种:
这种认证方式是浏览器遵守http协议实现的基本授权方式,HTTP协议进行通信的过程中,HTTP协议定义了基本认证认证允许HTTP服务器对客户端进行用户身份证的方法。
目前基本没有再使用这种认证方式的,一些老项目的内网认证可能还会有.
这里大概提一下验证过程,主要参考这篇文章
认证过程: 1. 客户端向服务器请求数据,请求的内容可能是一个网页或者是一个ajax异步请求,此时,假设客户端尚未被验证,则客户端提供如下请求至服务器:
Get /index.html HTTP/1.0 Host:www.google.com
2. 服务器向客户端发送验证请求代码401,( WWW-Authenticate: Basic realm=”google.com”
这句话是关键,如果没有客户端不会 弹出用户名和密码输入界面)服务器返回的数据大抵如下:
HTTP/1.0 401 Unauthorised Server: SokEvo/1.0 WWW-Authenticate: Basic realm="google.com" Content-Type: text/html Content-Length: xxx
3. 当符合http1.0或1.1规范的客户端(如IE,FIREFOX)收到401返回值时,将自动弹出一个登录窗口,要求用户输入用户名和密码。
4. 用户输入用户名和密码后,将 用户名及密码以BASE64加密方式加密(base64不安全!),并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成如下内容:
Get /index.html HTTP/1.0 Host:www.google.com Authorization: Basic d2FuZzp3YW5n
注:d2FuZzp3YW5n表示加密后的用户名及密码(用户名:密码 然后通过base64加密,加密过程是浏览器默认的行为,不需要我们人为加密,我们只需要输入用户名密码即可)
5. 服务器收到上述请求信息后,将Authorization字段后的用户信息取出、解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端
效果: 客户端未未认证的时候,会弹出用户名密码输入框,这个时候请求时属于pending状态, 这个时候其实服务当用户输入用户名密码的时候客户端会再次发送带Authentication头的请求。
这个方式是利用服务器端的session(会话)和浏览器端的cookie来实现前后端的认证, 由于http请求时是无状态的,服务器正常情况下是不知道当前请求之前有没有来过,这个时候我们如果要记录状态,就需要在服务器端创建一个会话(session),将同一个客户端的请求都维护在各自得会会话中,每当请求到达服务器端的时候,先去查一下该客户端有没有在服务器端创建session,如果有则已经认证成功了,否则就没有认证。
认证过程:
1,服务器在接受客户端首次访问时在服务器端创建session,然后保存session(我们可以将session保存在内存中,也可以保存在redis中,推荐使用后者),然后给这个session生成一个唯一的标识字符串,然后在响应头中种下这个唯一标识字符串。
2.签名。这一步只是对sid进行加密处理,服务端会根据这个secret密钥进行解密。(非必需步骤)
3.浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,浏览器在下次http请求的请求头中会带上该域名下的cookie信息,
4.服务器在接受客户端请求时会去解析请求头cookie中的sid,然后根据这个sid去找服务器端保存的该客户端的session,然后判断该请求是否合法。
弊端:
服务器内存消耗大: 用户每做一次应用认证,应用就会在服务端做一次记录,以方便用户下次请求时使用,通常来讲session保存在内存中,随着认证用户的增加,服务器的消耗就会很大.
易受到CSRF攻击: 基于cookie的一种跨站伪造攻击, 基于cookie来进行识别用户的话,用户本身就携带了值,cookie被截获,用户就很容易被伪造.
token是用户身份的验证方式,我们通常叫它:令牌。当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可, 无需再次带上用户名和密码。
最简单的token组成
我们可以把Token想象成一个安全的护照。你在一个安全的前台验证你的身份(通过你的用户名和密码),如果你成功验证了自己,你就可以取得这个。当你走进大楼的时候(试图从调用API获取资源),你会被要求验证你的护照,而不是在前台重新验证。
大概的流程是这样的:
总的来说就是客户端在首次登陆以后,服务端再次接收http请求的时候,就只认token了,请求只要每次把token带上就行了,服务器端会拦截所有的请求,然后校验token的合法性,合法就放行, 不合法就返回401(鉴权失败)。
优点:
服务器只需要对浏览器传来的token值进行解密,解密完成后进行用户数据的查询,如果查询成功,则通过认证.所以,即时有了多台服务器,服务器也只是做了token的解密和用户数据的查询, 它不需要在服务端去保留用户的认证信息或者会话信息,这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利,解决了session扩展性的弊端。
缺点:
Token过期:
token是访问特定资源的凭证,出于安全考虑,肯定是要有过期时间的。要不然一次登录便可能一直使用,那token认证还有什么意义? token可定是有过期时间的,一般不会很长,不会超高一个小时.
Refresh Token :
为什么需要refresh token?
如果token过期了,就要重新获取。继续重复第一次获取token的过程(比如登录,扫描授权等),每一小时就必须获取一次! 这样做是非常不好的用户体验。为了解决这个问题,于是就有了refresh token. 通过refresh token去重新获取新的 token.
refresh token,也是加密字符串,并且和token是相关联的。与获取资源的token不同, refresh token的作用仅仅是获取新的token,因此其作用和安全性要求都较低,所以其过期时间也可以设置得长一些,可以以天为最小单位。当然如果refresh token过期了,还是需要重新登录验证的.
阮一峰老师这篇关于JWT的文章,真的是写得非常好,也被很多人大段摘抄引用.对JWT不了解的同学可以直接查看这篇文章,我这里就不copy了.这里我只重点总结一下.
JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户.之后用户与服务器通信的时候.服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候, 会加上签名。
jwt最大的特点就是: 服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。
它是一个很长的 字符串,中间用点(.)分隔成三个部分。
分别是
{ "alg": "HS256","typ": "JWT"}
.alg属性表示签名的算法.默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。头部的 JSON 对象使用 Base64URL 算法转成字符串。
注意: JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
首次登录时,后端服务器判断用户账号密码正确之后,根据用户id、用户名、定义好的秘钥、过期时间生成 token ,返回给前端; 前端拿到后端返回的 token ,存储在 localStroage 和 Vuex 里; 前端每次路由跳转,判断 localStroage 有无 token ,没有则跳转到登录页,有则请求获取用户信息,改变登录状态; 每次请求接口,在 Axios 请求头里携带 token; 后端接口判断请求头有无 token,没有或者 token 过期,返回401; 前端得到 401 状态码,重定向到登录页面。
前面说过JWT一旦签发了,就不再收服务端控制了.因为它在服务端没有记录,是无状态的,是它最大的优点也是最大的缺点.这样就会造成一种不可控性.
例如:如果用户修改了,那他之前未到期的token怎么废弃掉???此时服务端是没有记录的,它是不知道哪些未到期的token是被废弃了的.为了解决这个问题,其实是 没有完美的方法的! 都需要后端添加状态,只是那种方法开销最小.
目前常见的处理方法有:
这里就简单说下第二种方法:黑名单
1,在签发的jwt中payload加入一个为随机字符的字段 token_id
.
2, 在服务端的分布式缓存上保存一份"groupId"黑名单。如果用户的jwt重置密码等需要作废已经签发但未过期的jwt时,就将该之前用户的"token__id"存入到黑名单中。并分配给他一个新的"token__id"到token中.
3,存入到黑名单中的"token__id"会设置一个过期时间.过期后"token_id"自动从黑名单中删除。
4,所有需要做JWT有效性校验的服务器,启动时访问分布式缓存. 将黑名单下载到本地内存。并且订阅分布式缓存的消息推送功能,在黑名单发生增删的时候,接收推送消息同步修改内存中的黑名单列表。
5,服务器做JWT校验的时候,除了校验过期时间,还要查询内存中的黑名单列表。若在黑名单中,则判定该JWT为失效。
虽然黑名单还是做了分布式存储,但黑名单本身的体积和使用频率却很低,所以开销很小.
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中, 用户只需要登录一次就可以访问所有相互信任的应用系统。
SSO一般都需要一个独立的认证中心(passport),子系统的登录均得通过passport,子系统本身将不参与登录操作,当一个系统成功登录以后,passport将会颁发一个令牌给各个子系统,子系统可以拿着令牌会获取各自的受保护资源,为了减少频繁认证,各个子系统在被passport授权以后,会建立一个局部会话,在一定时间内可以无需再次向passport发起认证
用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话,用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心,全局会话与局部会话有如下约束关系
注销:
sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作。
OAuth即开发授权,其实和SSO比较像.它允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容,为了保护用户数据的安全和隐私,第三方网站访问用户数据前都需要显式的向用户征求授权。我们常见的提供OAuth认证服务的厂商有QQ,微信,微博等。
限于篇幅,这里推荐还是阮一峰老师的文章
本文作者:前端小毛
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!