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

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

Cookie + Session 登录

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

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

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

有了 Cookie 之后,服务器端就能够获取到客户端传递过来的信息了,如果需要对信息进行验证,还需要通过 Session。

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

有了 Cookie 和 Session 之后,我们就可以进行登录认证了。

Cookie + Session  实现流程

Cookie + Session 的登录方式是最经典的一种登录方式,现在仍然有大量的企业在使用。

用户首次登录时:


  1. 用户访问 a.com/pageA,并输入密码登录。
  2. 服务器验证密码无误后,会创建 SessionId,并将它保存起来。
  3. 服务器端响应这个 HTTP 请求,并通过 Set-Cookie 头信息,将 SessionId 写入 Cookie 中。

服务器端的 SessionId 可能存放在很多地方,例如:内存、文件、数据库等。

第一次登录完成之后,后续的访问就可以直接使用 Cookie 进行身份验证了:


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

Cookie + Session  存在的问题

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

  • 由于服务器端需要对接大量的客户端,也就需要存放大量的 SessionId,这样会导致服务器压力过大。
  • 如果服务器端是一个集群,为了同步登录态,需要将 SessionId 同步到每一台机器上,无形中增加了服务器端维护成本。
  • 由于 SessionId 存放在 Cookie 中,所以无法避免 CSRF 攻击。

Token 登录

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

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

Token 机制实现流程

用户首次登录时:


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

后续页面访问时:


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

Token 机制的特点

根据上面的案例,我们可以分析出 Token 的优缺点:

  • 服务器端不需要存放 Token,所以不会对服务器端造成压力,即使是服务器集群,也不需要增加维护成本。
  • Token 可以存放在前端任何地方,可以不用保存在 Cookie 中,提升了页面的安全性。
  • Token 下发之后,只要在生效时间之内,就一直有效,如果服务器端想收回此 Token 的权限,并不容易。

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 计算如下:

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 单点登录

单点登录指的是在公司内部搭建一个公共的认证中心,公司下的所有产品的登录都可以在认证中心里完成,一个产品在认证中心登录后,再去访问另一个产品,可以不用再次登录,即可获取登录状态。

SSO 机制实现流程

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


  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 下的其他页面:


这个时候,由于 a.com 存在已登录的 Cookie 信息,所以服务器端直接认证成功。


如果认证中心登录完成之后,访问 b.com 下的页面:


这个时候,由于认证中心存在之前登录过的 Cookie,所以也不用再次输入账号密码,直接返回第 4 步,下发 ticket 给 b.com 即可。

SSO 单点登录退出

目前我们已经完成了单点登录,在同一套认证中心的管理下,多个产品可以共享登录态。现在我们需要考虑退出了,即:在一个产品中退出了登录,怎么让其他的产品也都退出登录?

原理其实不难,可以回过头来看第 5 步,每一个产品在向认证中心验证 ticket 时,其实可以顺带将自己的退出登录 api 发送到认证中心。

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

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

OAuth 第三方登录

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

其实是有的,很多大厂都会提供自己的第三方登录服务,我们一起来分析一下。


OAuth 机制实现流程

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


  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 第三方登录,简单易用,对用户和开发者都友好,但第三方平台很多,需要选择合适自己的第三方登录平台。

◆ ◆ ◆  ◆ 

你的在看我当成喜欢

yii2 获取同一个账号登录的所有session_前端登录方案?这一篇就够了相关推荐

  1. 保证同一个账号同时只能在一个设备上登录

    2019独角兽企业重金招聘Python工程师标准>>> 一.使用redis存token redis key设计 access_token_{token}:{userInfoJsonS ...

  2. 使用flask-WTF,Flask-Login,sqlite3实现登录和注册(前端登录和注册页面)

    文章目录 1.文件结构: 2.实现效果: 3.使用的可视化工具(工具DB Browser for sqlite下载): 4.参考过的文章(一部分代码来自这里): 5.主文件.main.py: 6.前端 ...

  3. iOS 准确获取 iPhone 状态栏、导航栏、TabBar高度,看这篇就够了

    前言 最近在项目开发的时候,发现项目提供的获取 「状态栏+导航栏高度」的方法,在 iPhone 12 系列机型上是错误的.解决了这个问题之后,决定做个简单的总结,于是有了这篇文章. 本文主要是分析了遇 ...

  4. 如何做到同一个账号同一时段只能登录一个

    在许多web项目中,需要禁止用户重复登录.一般来说有两种做法: 一是在用户表中维护一个字段isOnLine(是否在线),用户登录时,设定值为true,用户退出时设定为false,在重复登录时,检索到该 ...

  5. 第五天 01-ftp服务器使用及arp欺骗获取ftp账号密码

    windows ftp服务器使用 概述 FTP:File Transfor Protocol,文件传输协议. 端口号: 主动模式:当FTP服务开启时,TCP21端口号开启,该端口号称为控制端口. TC ...

  6. 顺序消费可没你想的这么简单,队列数量的变更往往无法保证同一个账号的消息发送到同一个分区,怎么解决?

    掌握一到两门java主流中间件,是敲开BAT等大厂必备的技能,送给大家一个Java中间件学习路线,助力大家实现职场的蜕变. Java进阶之梯,成长路线与学习资料,助力突破中间件领域 在金融行业中,如果 ...

  7. c#ras获取宽带账号密码_如何将远程科学Ras pi数据获取到基于云的仪表板

    c#ras获取宽带账号密码 This post is a learning experience for myself figuring out a way to get my data from a ...

  8. iphone数据传输已取消怎么办_苹果同一个账号不想同步传输 苹果同一个id怎么取消同步...

    苹果同一个账号不想同步传输怎么办及苹果同一个id怎么取消同步是很多人问到的,在购买了新的设备之后,登录同一个账号会发现所有的内容都同步了,有点尴尬,那么苹果同一个id怎么取消同步呢? 首先你要了解到, ...

  9. 5.2.2 利用arp中间人攻击获取管理员账号密码

    一.arp协议简述: ARP即地址解析协议,用于IP地址到MAC地址的映射,即由目标IP找到对应的MAC地址.ARP协议特点是"广播请求,单播回应". 二.arp欺骗原理:(看图, ...

最新文章

  1. 如何使用WindowsLiveWriter发文章
  2. python 打开当前目录的txt文件-Python - 读取其他文件夹/目录中的文本文件
  3. 我用Java写了个女朋友,甚至还能跟我聊两句!?
  4. 安卓Dialog对话框多次显示而闪退的解决办法
  5. 使用移动自适应布局+easy mock实现移动界面的简单实现
  6. css 大图保持宽高比压缩,css 保持宽高比缩放
  7. 低代码,填补业务技术鸿沟 or 紧贴业务的开发时代?
  8. 用asp.net+Jquery+Ajax+sqlserver编写的 (英语六级记单词)
  9. 优麒麟 20.04 LTS 版本发布,UKUI3.0 灵动转身
  10. SpringCloud分布式开发五大组件详解
  11. 1.1 echo rem cd dir命令
  12. 11.Handle assignment to self in operator =
  13. D. Array Splitting
  14. MATLAB处理txt文档数据——以处理pscad输出数据为例
  15. psn请验证您不是机器人_PS4无法登陆PSN的解决办法
  16. Thinking -- CSS从根解决选择前一个兄弟元素
  17. 物联网卡解决智能安防系统监控难题,开启全新安防时代
  18. Go语言Win10环境配置
  19. 一个工科研究生毕业后的职业规划
  20. CCNP642-825实验题题库

热门文章

  1. 5g宣传方案_5G时代来了,VR如何玩转线上营销新模式
  2. python utf 8_python写utf-8文件的问题
  3. mysql限制小数位_Mysql中设置小数点用什么数据类型 decimal
  4. 车辆动力学及控制pdf_Simulink软件仿真平台之车辆模型
  5. java ordered list_关于并行处理:Java 8的forEachOrdered()和sequence()方法之间的区别?...
  6. linux交换分区的目录,linux 下的交换分区及根目录
  7. 属于哪种虚拟化类型_经络淤堵,疲乏无力?有3种疲劳类型,你属于哪种,快来自测一下...
  8. 一键进入dfu模式软件_dfu模式是什么 dfu模式介绍及进入方法【详解】
  9. kdj买卖指标公式源码_“点金主图+副图+KDJ排序指标”公式源码
  10. php仓储管理系统 eku_河南物流仓储外包哪里有 极鹭云仓