前端面试查漏补缺--(十) 前端鉴权

前言

本系列最开始是为了本身面试准备的.后来发现整理愈来愈多,差很少有十二万字符,最后决定仍是分享出来给你们.html

为了分享整理出来,花费了本身大量的时间,起码是只本身用的三倍时间.若是喜欢的话,欢迎收藏,关注我!谢谢!前端

文章连接

合集篇:

前端面试查漏补缺--Index篇(12万字符合集) 包含目前已写好的系列其余十几篇文章.后续新增值文章不会再在每篇添加连接,强烈建议议点赞,关注合集篇!!!!,谢谢!~vue

后续更新计划

后续还会继续添加设计模式,前端工程化,项目流程,部署,闭环,vue常考知识点 等内容.若是以为内容不错的话欢迎收藏,关注我!谢谢!ios

求一分内推

目前本人也在准备跳槽,但愿各位大佬和HR小姐姐能够内推一份靠谱的武汉 前端岗位!邮箱:bupabuku@foxmail.com.谢谢啦!~web

常见鉴权方式

目前咱们经常使用的鉴权有四种:面试

  1. HTTP Basic Authentication (HTTP基本认证)
  2. session-cookie
  3. Token 验证(包括JWT,SSO)
  4. OAuth(开放受权)

HTTP Basic Authentication

这种认证方式是浏览器遵照http协议实现的基本受权方式,HTTP协议进行通讯的过程当中,HTTP协议定义了基本认证认证容许HTTP服务器对客户端进行用户身份证的方法。ajax

目前基本没有再使用这种认证方式的,一些老项目的内网认证可能还会有.redis

这里大概提一下验证过程,主要参考这篇文章算法

认证过程:   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

这个方式是利用服务器端的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组成:uid(用户惟一的身份标识)、time(当前时间的时间戳)、sign(签名,由token的前几位+盐以哈希算法压缩成必定长的十六进制字符串,能够防止恶意第三方拼接token请求服务器)。还能够把不变的参数也放进token,避免屡次查库。

咱们能够把Token想象成一个安全的护照。你在一个安全的前台验证你的身份(经过你的用户名和密码),若是你成功验证了本身,你就能够取得这个。当你走进大楼的时候(试图从调用API获取资源),你会被要求验证你的护照,而不是在前台从新验证。

验证流程

大概的流程是这样的:

  • 1, 客户端使用用户名跟密码请求登陆
  • 2, 服务端收到请求,去验证用户名与密码
  • 3, 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  • 4, 客户端收到 Token 之后能够把它存储起来,好比放在 Cookie 里或者 Local Storage 里
  • 5, 客户端每次向服务端请求资源的时候须要带着服务端签发的 Token
  • 6, 服务端收到请求,而后去验证客户端请求里面带着的 Token,若是验证成功,就向客户端返回请求的数据

总的来讲就是客户端在首次登录之后,服务端再次接收http请求的时候,就只认token了,请求只要每次把token带上就好了,服务器端会拦截全部的请求,而后校验token的合法性,合法就放行,不合法就返回401(鉴权失败)。

Token优势与缺点

优势:

  • Token 彻底由应用管理,因此它能够避开同源策略. (Cookie是不容许垮域访问的,token不存在)
  • Token 能够避免 CSRF 攻击(也是由于不须要cookie了)
  • Token 能够是无状态的,能够在多个服务间共享
  • Token 支持手机端访问(Cookie不支持手机端访问)

服务器只须要对浏览器传来的token值进行解密,解密完成后进行用户数据的查询,若是查询成功,则经过认证.因此,即时有了多台服务器,服务器也只是作了token的解密和用户数据的查询,它不须要在服务端去保留用户的认证信息或者会话信息,这就意味着基于token认证机制的应用不须要去考虑用户在哪一台服务器登陆了,这就为应用的扩展提供了便利,解决了session扩展性的弊端。

缺点:

  • 占带宽: 正常状况下token要比 session_id更大,须要消耗更多流量,挤占更多带宽.(不过几乎能够忽略)
  • 性能问题: 相比于session-cookie来讲,token须要服务端花费更多的时间和性能来对token进行解密验证.其实Token相比于session-cookie来讲就是一个"时间换空间"的方案.

Token与session的区别

  • 1. 使用Token,服务端不须要保存状态. 在session中sessionid 是一个惟一标识的字符串,服务端是根据这个字符串,来查询在服务器端保持的session,这里面才保存着用户的登录状态。可是token自己就是一种登录成功凭证,他是在登录成功后根据某种规则生成的一种信息凭证,他里面自己就保存着用户的登录状态。服务器端只须要根据定义的规则校验这个token是否合法就行。

  • 2. Token不须要借助cookie的. session-cookie是须要cookie配合的,那么在http代理客户端的选择上就只有浏览器了,由于只有浏览器才会去解析请求响应头里面的cookie,而后每次请求再默认带上该域名下的cookie。可是咱们知道http代理客户端不仅有浏览器,还有原生APP等等,这个时候cookie是不起做用的,或者浏览器端是能够禁止cookie的(虽然能够,可是这基本上是属于吃饱没事干的人干的事),可是token 就不同,他是登录请求在登录成功后再请求响应体中返回的信息,客户端在收到响应的时候,能够把他存在本地的cookie,storage,或者内存中,而后再下一次请求的请求头重带上这个token就好了。简单点来讲cookie-session机制他限制了客户端的类型,而token验证机制丰富了客户端类型。

  • 3. 时效性。session-cookie的sessionid实在登录的时候生成的并且在登出事时一直不变的,在必定程度上安全就会低,而token是能够在一段时间内动态改变的。

  • 4. 可扩展性。token验证自己是比较灵活的,一是token的解决方案有许多,经常使用的是JWT,二来咱们能够基于token验证机制,专门作一个鉴权服务,用它向多个服务的请求进行统一鉴权。

Token过时与Refresh Token

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 (JSON Web Tokens)

阮一峰老师这篇关于JWT的文章,真的是写得很是好,也被不少人大段摘抄引用.对JWT不了解的同窗能够直接查看这篇文章,我这里就不copy了.这里我只重点总结一下.

JWT原理

JWT 的原理是,服务器认证之后,生成一个 JSON 对象,发回给用户.以后用户与服务器通讯的时候.服务器彻底只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名

jwt最大的特色就是: 服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

JWT 的数据结构

它是一个很长的字符串,中间用点(.)分隔成三个部分。

分别是:Header(头部).Payload(负载).Signature(签名)

  • Header : 部分是一个 JSON 对象,描述 JWT 的元数据,例如:{ "alg": "HS256","typ": "JWT"}.alg属性表示签名的算法.默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。

头部的 JSON 对象使用 Base64URL 算法转成字符串。

  • Payload: 部分也是一个 JSON 对象,用来存放实际须要传递的数据。这个 JSON 对象也要使用 Base64URL 算法转成字符串。

注意: JWT 默认是不加密的,任何人均可以读到,因此不要把秘密信息放在这个部分。

  • Signature: 部分是对前两部分的签名,防止数据篡改。 首先,须要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。而后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256).

JWT 的几个特色

  • (1)JWT 默认是不加密,但也是能够加密的。生成原始 Token 之后,能够用密钥再加密一次。
  • (2)JWT 不加密的状况下,不能将秘密数据写入 JWT。
  • (3)JWT 不只能够用于认证,也能够用于交换信息。有效使用 JWT,能够下降服务器查询数据库的次数。
  • (4)JWT 的最大缺点是,因为服务器不保存 session 状态,所以没法在使用过程当中废止某个 token,或者更改 token的权限。也就是说,一旦 JWT 签发了,在到期以前就会始终有效,除非服务器部署额外的逻辑。
  • (5)JWT 自己包含了认证信息,一旦泄露,任何人均可以得到该令牌的全部权限。为了减小盗用,JWT的有效期应该设置得比较短。 对于一些比较重要的权限,使用时应该再次对用户进行认证。
  • (6)为了减小盗用,JWT 不该该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

首次登陆时,后端服务器判断用户帐号密码正确以后,根据用户id、用户名、定义好的秘钥、过时时间生成 token ,返回给前端; 前端拿到后端返回的 token ,存储在 localStroage 和 Vuex 里; 前端每次路由跳转,判断 localStroage 有无 token ,没有则跳转到登陆页,有则请求获取用户信息,改变登陆状态; 每次请求接口,在 Axios 请求头里携带 token; 后端接口判断请求头有无 token,没有或者 token 过时,返回401; 前端获得 401 状态码,重定向到登陆页面。

补充: 后端主动让JWT失效的方法

前面说过JWT一旦签发了,就再也不收服务端控制了.由于它在服务端没有记录,是无状态的,是它最大的优势也是最大的缺点.这样就会形成一种不可控性.

例如:若是用户修改了,那他以前未到期的token怎么废弃掉???此时服务端是没有记录的,它是不知道哪些未到期的token是被废弃了的.为了解决这个问题,实际上是没有完美的方法的! 都须要后端添加状态,只是那种方法开销最小.

目前常见的处理方法有:

  • 1,将 token 存入 DB(如 Redis)中,失效则删除;但增长了一个每次校验时候都要先从 DB 中查询 token是否存在的步骤,并且违背了 JWT 的无状态原则(不推荐)。
  • 2,维护一个 token 黑名单,失效则加入黑名单中(用的比较多)。
  • 3,在 JWT 中增长一个版本号字段,失效则改变该版本号。
  • 4,在服务端设置加密的 key 时,为每一个用户生成惟一的 key,失效则改变该 key。

这里就简单说下第二种方法:黑名单

  • 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发起认证

单点登陆流程

  • 用户访问系统1的受保护资源,系统1发现用户未登陆,跳转至sso认证中心,并将本身的地址做为参数
  • sso认证中心发现用户未登陆,将用户引导至登陆页面
  • 用户输入用户名密码提交登陆申请
  • sso认证中心校验用户信息,建立用户与sso认证中心之间的会话,称为全局会话,同时建立受权令牌
  • sso认证中心带着令牌跳转会最初的请求地址(系统1)
  • 系统1拿到令牌,去sso认证中心校验令牌是否有效
  • sso认证中心校验令牌,返回有效,注册系统1
  • 系统1使用该令牌建立与用户的会话,称为局部会话,返回受保护资源
  • 用户访问系统2的受保护资源
  • 系统2发现用户未登陆,跳转至sso认证中心,并将本身的地址做为参数
  • sso认证中心发现用户已登陆,跳转回系统2的地址,并附上令牌
  • 系统2拿到令牌,去sso认证中心校验令牌是否有效
  • sso认证中心校验令牌,返回有效,注册系统2
  • 系统2使用该令牌建立与用户的局部会话,返回受保护资源

用户登陆成功以后,会与sso认证中心及各个子系统创建会话,用户与sso认证中心创建的会话称为全局会话,用户与各个子系统创建的会话称为局部会话,局部会话创建以后,用户访问子系统受保护资源将再也不经过sso认证中心,全局会话与局部会话有以下约束关系

  • 局部会话存在,全局会话必定存在
  • 全局会话存在,局部会话不必定存在
  • 全局会话销毁,局部会话必须销毁

注销:

sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知全部注册系统执行注销操做。

  • 用户向系统1发起注销请求
  • 系统1根据用户与系统1创建的会话id拿到令牌,向sso认证中心发起注销请求
  • sso认证中心校验令牌有效,销毁全局会话,同时取出全部用此令牌注册的系统地址
  • sso认证中心向全部注册系统发起注销请求
  • 各注册系统接收sso认证中心的注销请求,销毁局部会话
  • sso认证中心引导用户至登陆页面

OAuth 2.0

OAuth即开发受权,其实和SSO比较像.它容许用户受权第三方网站访问他们存储在另外的服务提供者上的信息,而不须要将用户名和密码提供给第三方网站或分享他们数据的全部内容,为了保护用户数据的安全和隐私,第三方网站访问用户数据前都须要显式的向用户征求受权。咱们常见的提供OAuth认证服务的厂商有QQ,微信,微博等。

限于篇幅,这里推荐仍是阮一峰老师的文章

感谢及参考