4种常规的登陆认证方式

登陆是每一个网站中都常常用到的一个功能,在页面上咱们输入帐号密码,敲一下回车键,就登陆了,但这背后的登陆原理你是否清楚呢?今天咱们就来介绍几种经常使用的登陆方式。前端

  • Cookie + Session 登陆
  • Token 登陆
  • SSO 单点登陆
  • OAuth 第三方登陆

Cookie + Session 登陆

HTTP 是一种无状态的协议,客户端每次发送请求时,首先要和服务器端创建一个链接,在请求完成后又会断开这个链接。这种方式能够节省传输时占用的链接资源,但同时也存在一个问题:每次请求都是独立的,服务器端没法判断本次请求和上一次请求是否来自同一个用户,进而也就没法判断用户的登陆状态。算法

为了解决 HTTP 无状态的问题,Lou Montulli 在 1994 年的时候,推出了 Cookie。数据库

Cookie 是服务器端发送给客户端的一段特殊信息,这些信息以文本的方式存放在客户端,客户端每次向服务器端发送请求时都会带上这些特殊信息。

有了 Cookie 以后,服务器端就可以获取到客户端传递过来的信息了,若是须要对信息进行验证,还须要经过 Session。后端

客户端请求服务端,服务端会为此次请求开辟一块内存空间,这个即是 Session 对象。

有了 Cookie 和 Session 以后,咱们就能够进行登陆认证了。api

1. Cookie + Session 实现流程

Cookie + Session 的登陆方式是最经典的一种登陆方式,如今仍然有大量的企业在使用。浏览器

用户首次登陆时:
image.png安全

  1. 用户访问 a.com/pageA,并输入密码登陆。
  2. 服务器验证密码无误后,会建立 SessionId,并将它保存起来。
  3. 服务器端响应这个 HTTP 请求,并经过 Set-Cookie 头信息,将 SessionId 写入 Cookie 中。
  4. 浏览器会根据Set-Cookie中的信息,自动将SessionId存储至cookie中。
服务器端的 SessionId 可能存放在不少地方,例如:内存、文件、数据库等。

第一次登陆完成以后,后续的访问就能够直接使用 Cookie 进行身份验证了:服务器

image.png

  1. 用户访问 a.com/pageB 页面时,会自动带上第一次登陆时写入的 Cookie。
  2. 服务器端比对 Cookie 中的 SessionId 和保存在服务器端的 SessionId 是否一致。
  3. 若是一致,则身份验证成功。

2. Cookie + Session 存在的问题

虽然咱们使用 Cookie + Session 的方式完成了登陆验证,但仍然存在一些问题:微信

  • 因为服务器端须要对接大量的客户端,也就须要存放大量的 SessionId,这样会致使服务器压力过大。
  • 若是服务器端是一个集群,为了同步登陆态,须要将 SessionId 同步到每一台机器上,无形中增长了服务器端维护成本。
  • 因为 SessionId 存放在 Cookie 中,因此没法避免 CSRF 攻击。

Token 登陆认证

为了解决 Session + Cookie 机制暴露出的诸多问题,咱们可使用 Token 的登陆方式。cookie

Token是服务端生成的一串字符串,以做为客户端请求的一个令牌。当第一次登陆后,服务器会生成一个 Token 并返回给客户端,客户端后续访问时,只需带上这个 Token 便可完成身份认证。

1. Token 机制实现流程

用户首次登陆时:

image.png

  1. 用户输入帐号密码,并点击登陆。
  2. 服务器端验证帐号密码无误,建立 Token。
  3. 服务器端将 Token 返回给客户端,由客户端自由保存

后续页面访问时:

image.png

  1. 用户访问 a.com/pageB 时,带上第一次登陆时获取的 Token。
  2. 服务器端验证 Token ,有效则身份验证成功。

2. Token 机制的特色

根据上面的案例,咱们能够分析出 Token 的优缺点:

  • 服务器端不须要存放 Token,因此不会对服务器端形成压力,即便是服务器集群,也不须要增长维护成本。
  • Token 能够存放在前端任何地方,能够不用保存在 Cookie 中,提高了页面的安全性。
  • Token 下发以后,只要在生效时间以内,就一直有效,若是服务器端想收回此 Token 的权限,并不容易。

3. Token 的生成方式

最多见的 Token 生成方式是使用 JWT(Json Web Token),它是一种简洁的,自包含的方法用于通讯双方之间以 JSON 对象的形式安全的传递信息。

上文中咱们说到,使用 Token 后,服务器端并不会存储 Token,那怎么判断客户端发过来的 Token 是合法有效的呢?

答案其实就在 Token 字符串中,其实 Token 并非一串杂乱无章的字符串,而是经过多种算法拼接组合而成的字符串,咱们来具体分析一下。

JWT 算法主要分为 3 个部分:header(头信息),playload(消息体),signature(签名)。

header 部分指定了该 JWT 使用的签名算法:

header = '{"alg":"HS256","typ":"JWT"}' // `HS256` 表示使用了 HMAC-SHA256 来生成签名。

playload 部分代表了 JWT 的意图:

payload = '{"loggedInAs":"admin","iat":1422779638}' //iat 表示令牌生成的时间

signature 部分为 JWT 的签名,主要为了让 JWT 不能被随意篡改,签名的方法分为两个步骤:

  1. 输入 base64url 编码的 header 部分、 .base64url 编码的 playload 部分,输出 unsignedToken。
  2. 输入服务器端私钥、unsignedToken,输出 signature 签名。
const base64Header = encodeBase64(header)
const base64Payload = encodeBase64(payload)
const unsignedToken = `${base64Header}.${base64Payload}`
const key = '服务器私钥'

signature = HMAC(key, unsignedToken)

最后的 Token 计算以下:
最后的 Token 计算以下:

const base64Header = encodeBase64(header)
const base64Payload = encodeBase64(payload)
const base64Signature = encodeBase64(signature)

token = `${base64Header}.${base64Payload}.${base64Signature}`

服务器在判断 Token 时:

const [base64Header, base64Payload, base64Signature] = token.split('.')

const signature1 = decodeBase64(base64Signature)
const unsignedToken = `${base64Header}.${base64Payload}`
const signature2 = HMAC('服务器私钥', unsignedToken)

if(signature1 === signature2) {
  return '签名验证成功,token 没有被篡改'
}

const payload =  decodeBase64(base64Payload)
if(new Date() - payload.iat < 'token 有效期'){
  return 'token 有效'
}

有了 Token 以后,登陆方式已经变得很是高效,接下来咱们介绍另外两种登陆方式。


SSO 单点登陆

单点登陆指的是在公司内部搭建一个公共的认证中心,公司下的全部产品的登陆均可以在认证中内心完成,一个产品在认证中心登陆后,再去访问另外一个产品,能够不用再次登陆,便可获取登陆状态。

1. SSO 机制实现流程

用户首次访问时,须要在认证中心登陆:

image.png

  1. 用户访问网站 a.com 下的 pageA 页面。
  2. 因为没有登陆,则会重定向到认证中心,并带上回调地址 www.sso.com?return_uri=a.com/pageA,以便登陆后直接进入对应页面。
  3. 用户在认证中心输入帐号密码,提交登陆。
  4. 认证中心验证帐号密码有效,而后重定向 a.com?ticket=123 带上受权码 ticket,并将认证中心 sso.com 的登陆态写入 Cookie。
  5. a.com 服务器中,拿着 ticket 向认证中心确认,受权码 ticket 真实有效。
  6. 验证成功后,服务器将登陆信息写入 Cookie(此时客户端有 2 个 Cookie 分别存有 a.comsso.com 的登陆态)。

认证中心登陆完成以后,继续访问 a.com 下的其余页面:

image.png

这个时候,因为 a.com 存在已登陆的 Cookie 信息,因此服务器端直接认证成功。

若是认证中心登陆完成以后,访问 b.com 下的页面:

image.png

这个时候,因为认证中心存在以前登陆过的 Cookie,因此也不用再次输入帐号密码,直接返回第 4 步,下发 ticket 给 b.com 便可。

2. SSO 单点登陆退出

目前咱们已经完成了单点登陆,在同一套认证中心的管理下,多个产品能够共享登陆态。如今咱们须要考虑退出了,即:在一个产品中退出了登陆,怎么让其余的产品也都退出登陆?

原理其实不难,能够回过头来看第 5 步,每个产品在向认证中心验证 ticket 时,其实能够顺带将本身的退出登陆 api 发送到认证中心。

当某个产品 c.com 退出登陆时:

  1. 清空 c.com 中的登陆态 Cookie。
  2. 请求认证中心 sso.com 中的退出 api。
  3. 认证中心遍历下发过 ticket 的全部产品,并调用对应的退出 api,完成退出。

OAuth 第三方登陆

在上文中,咱们使用单点登陆完成了多产品的登陆态共享,但都是创建在一套统一的认证中心下,对于一些小型企业,未免太麻烦,有没有一种登陆可以作到开箱即用?

实际上是有的,不少大厂都会提供本身的第三方登陆服务,咱们一块儿来分析一下。

image.png

1. OAuth 机制实现流程

这里以微信开放平台的接入流程为例:

image.png

  1. 首先,a.com 的运营者须要在微信开放平台注册帐号,并向微信申请使用微信登陆功能。
  2. 申请成功后,获得申请的 appid、appsecret。
  3. 用户在 a.com 上选择使用微信登陆。
  4. 这时会跳转微信的 OAuth 受权登陆,并带上 a.com 的回调地址。
  5. 用户输入微信帐号和密码,登陆成功后,须要选择具体的受权范围,如:受权用户的头像、昵称等。
  6. 受权以后,微信会根据拉起 a.com?code=123 ,这时带上了一个临时票据 code。
  7. 获取 code 以后, a.com 会拿着 code 、appid、appsecret,向微信服务器申请 token,验证成功后,微信会下发一个 token。
  8. 有了 token 以后, a.com 就能够凭借 token 拿到对应的微信用户头像,用户昵称等信息了。
  9. a.com 提示用户登陆成功,并将登陆状态写入 Cooke,以做为后续访问的凭证。

总结

本文介绍了 4 种常见的登陆方式,原理应该你们都清楚了,总结一下这 4 种方案的使用场景:

  • Cookie + Session 历史悠久,适合于简单的后端架构,需开发人员本身处理好安全问题。
  • Token 方案对后端压力小,适合大型分布式的后端架构,但已分发出去的 token ,若是想收回权限,就不是很方便了。
  • SSO 单点登陆,适用于中大型企业,想要统一内部全部产品的登陆方式。
  • OAuth 第三方登陆,简单易用,对用户和开发者都友好,但第三方平台不少,须要选择合适本身的第三方登陆平台。
相关文章
相关标签/搜索