type
status
date
slug
summary
tags
category
password
icon

登录和授权的区别

  • 登录:身份认证,即确认「你是你」的过程。
  • 授权:由身份或持有的令牌确认享有某些权限(例如获取⽤户信息)。⽽登录过程实质上的⽬的也 是为了确认权限。
因此,在实际的应⽤中,多数场景下的「登录」和「授权」界限是模糊的。

HTTP 中确认授权(或登录)的两种⽅式

  1. 通过 Cookie
  1. 通过 Authorization
 

Cookie

Cookie 的起源

网景公司想要做一个 Web 购物车的功能,不想把购物车的数据存在服务器。目的是为了让服务端可以把数据存在客户端。

Cookie 的工作机制

在客户端帮助服务端存储数据的机制。
  • 服务器需要客户端保存的内容,放在 Set-Cookie headers ⾥返回,客户端会⾃动保存。
  • 客户端保存的 Cookies,会在之后的所有请求⾥都携带进 Cookie header ⾥发回给服务器。
  • 客户端保存 Cookie 是按照服务器域名来分类的,例如 shop.com 发回的 Cookie 保存下来以 后,在之后向 games.com 的请求中并不会携带。
  • 客户端保存的 Cookie 在超时后会被删除、没有设置超时时间的 Cookie (称作 Session Cookie)在浏览器关闭后就会⾃动删除;另外,服务器也可以主动删除还未过期的客户端 Cookies。

Cookie 报文中的格式

统一个主机下 Cookie 的内容可以保存多个,以键值对保存
最后面的 HttpOnly 是可选项,用于防治跨站脚本攻击,这个标记表示该 Cookie 本地javascript 无法获取。
例如,用户在 shop.com 网站上购物
1.客户端先发送一个 POST 请求,表明想要向购物车添加一个苹果,
1.客户端先发送一个 POST 请求,表明想要向购物车添加一个苹果,
2.服务器接收到客户端的请求,发现购物车的东西不需要存在服务器,给出响应,表明你自己存在客户端吧(注意,这里的逻辑是由服务端开发者决定的,使用 cart 作为 key,但是 Cookie 的主要用处就是存储服务端想存的数据。)
2.服务器接收到客户端的请求,发现购物车的东西不需要存在服务器,给出响应,表明你自己存在客户端吧(注意,这里的逻辑是由服务端开发者决定的,使用 cart 作为 key,但是 Cookie 的主要用处就是存储服务端想存的数据。)
3.于是客户端就将当前域名和服务端计算后的想要存储的 Cookie 内容存储到本地的缓存中
3.于是客户端就将当前域名和服务端计算后的想要存储的 Cookie 内容存储到本地的缓存中
4.这时用户又想向购物车添加一个香蕉,于是发送了一个 Post 请求,这个 Post 请求客户端(浏览器)会自动将该 Host 之前保存的 Cookie 附加在 Cookie Header 中。
4.这时用户又想向购物车添加一个香蕉,于是发送了一个 Post 请求,这个 Post 请求客户端(浏览器)会自动将该 Host 之前保存的 Cookie 附加在 Cookie Header 中。
5.服务端接收到 Post 请求,经过处理,发现客户端想要新增一个香蕉到购物车,于是会从 Cookie Header 取出 cart 对应的 Value,发现之前购物车里已经有一个苹果了,加上这次的香蕉,那么把苹果和香蕉一起返回给客户端。(注意具体服务器会怎么处理数据并返回给客户端,是由服务端开发者决定的)
5.服务端接收到 Post 请求,经过处理,发现客户端想要新增一个香蕉到购物车,于是会从 Cookie Header 取出 cart 对应的 Value,发现之前购物车里已经有一个苹果了,加上这次的香蕉,那么把苹果和香蕉一起返回给客户端。(注意具体服务器会怎么处理数据并返回给客户端,是由服务端开发者决定的)
6.客户端(浏览器)发现这次服务器想让我们存苹果和香蕉。并且 key 值 cart 已经存在,那么直接把 value 进行覆盖更新就好了。(浏览器不会去计算 Cookie 只会无脑保存,已经有的 key 就覆盖,没有的创建)
6.客户端(浏览器)发现这次服务器想让我们存苹果和香蕉。并且 key 值 cart 已经存在,那么直接把 value 进行覆盖更新就好了。(浏览器不会去计算 Cookie 只会无脑保存,已经有的 key 就覆盖,没有的创建)

Cookie 的作用

  • 会话管理:登录状态,购物车
    • 例如:获取用户的个人信息,没有登录时不能获取的,那么服务端是怎么判断用户的登录状态的呢?目前很多的做法是使用 Cookie 保存一个 SessionId,
      1.用户通过客户端输入账号密码通过 Post 请求,发送给服务器
      1.用户通过客户端输入账号密码通过 Post 请求,发送给服务器
      2.服务端接收到登录请求,验证账号密码后,生成一个 sessionId 为 key 的 Cookie,返回给客户端。
      2.服务端接收到登录请求,验证账号密码后,生成一个 sessionId 为 key 的 Cookie,返回给客户端。
      3。客户端依旧无脑保存服务端返回的 Cookie
      3。客户端依旧无脑保存服务端返回的 Cookie
      4.这时,客户端想要获取用户信息,直接请求,浏览器会自动把 Cookie 带上,其中包含sessionId,服务端接收到后,发现这个 sessionId 在后端已经登录,并把对应的用户的信息返回给客户端。
      4.这时,客户端想要获取用户信息,直接请求,浏览器会自动把 Cookie 带上,其中包含sessionId,服务端接收到后,发现这个 sessionId 在后端已经登录,并把对应的用户的信息返回给客户端。
  • 个性化:用户偏好,主题
    • 例如:用户喜欢蓝牙的主题风格,怎么在用户下次打开网站时,直接显示蓝色的网站风格 是不是可以直接把主题编号保存到客户端的 Cookie,或者与用户 ID 进行绑定,每次用户打开网站时就能知道,这个用户之前偏好蓝色的主题,并返回蓝色风格的网站页面给到用户。
  • Tracking:分析用户行为
    • 例如下图所示的方式 1.用户在 shop.com 中访问了 3rd-party.com 的图片,3rd-party.com 发现用户是通过 shop.com 跳转过来的,就给这个用户生成一个 client_id,假设时 123。然后记录下这个用户访问过 shop.com 这个网站,并返回了一个 client_id 的 Cookie 给到用户的浏览器,浏览器会自动保存, 2.某一时间,用户访问 taobao.com 网站,其中也访问 3rd-party.com 的图片,那么这次图片访问,浏览器会自动把之前保存的 client_id=123 的 Cookie 发送到3rd-party.com,并且 3rd-party.com 也知道了你是从 taobao.com 访问的,就又记录下用户 123 又访问了淘宝。 如此反复记录,能够得到用户 123 的画像。就能够针对该用户提供定向广告。往往像3rd-party.com 这种不是一个网站,而是一群商业联盟,他们都互相传递并记录用户行为,以得到更精准的用户画像,谋求更大的利益。
      notion image
       

XSS(Cross-site scripting):HttpOnly

Cross-site scripting:跨站脚本攻击
由于 Cookie 是存在浏览器本地,javascript 能过获取到 Cookie,那么坏人就可以通过javascript 获取到 Cookie 去干坏事。
其中一种解决上述问题的方式是在报文的 set-cookie 的 key-value;的最后可以加上 HttpOnly,用于防治跨站脚本攻击,这个标记表示该 Cookie 本地 javascript 无法获取。

XSRF(Cross-site request forgery):Referer

Cross-site request forgery:跨站请求伪造
即在⽤户不知情的情况下访问已经保存了 Cookie 的⽹站,以此来越权操作⽤户账户(例如盗取⽤户资⾦)。应对⽅式主要是从服务器安全⻆度考虑,就不多说了。
由于页面跳转时浏览器会强制在跳转后的请求中加上一个 Referer 的 Header,并将跳转前的链接作为值,发送给新页面,新页面的后端如果需要安全考虑,就可以通过 Referer 这个Header 判断页面的安全性,并给出对应的响应。
应对⽅式:Referer 校验。
 
💡
使用 Cookie 去登录,是大家自己摸索出来的方式,目前被广泛使用。 但是移动端目前使用的不太多。并且 Cookie 的初衷并不是用于登录,Http 设计中,Authorization 这个 Header 是专门用于登录的,并且目前也开始被使用,以后也会成为主流

Authorization

Http 默认设计的登录授权的方式就是 Authorization,Cookie 的方式是开发摸索出来的
两种主流方式:Basic 和 Bearer

Basic

格式:
例如:有一个获取用户信息的请求 假设用户名是 man,密码是 123 ,man:123 的 base64是 bWFuOjEyMw==
安全风险:
如果报文被截获,base64 是可以解码获取到原始信息的。但是在 Https 中,整个报文都是密文,被截获,报文都是加密的。
另一种,在 Android 上,账号密码的明文往往保存在包内存储的,用于免登录,由于 Android 的安全机制,包内数据无法被外部获取,但是如果手机被 root 了,安装了木马程序,那么账号密码是可以被获取的,一但被获取,就只能改密码了。
这两种属于极端情况,
 

Bearer

Bearer(持票人)
格式:
bearer token 的获取方式:通过 OAuth2 的授权流程

OAuth2 授权流程:

  1. 第三⽅⽹站向授权⽅⽹站申请第三⽅授权合作,拿到 client id 和 client secret
  1. ⽤户在使⽤第三⽅⽹站时,点击「通过 XX (如 GitHub) 授权」按钮,第三⽅⽹站将⻚⾯跳转到授权⽅⽹站,并传⼊ client id 作为⾃⼰的身份标识
  1. 授权⽅⽹站根据 client id ,将第三⽅⽹站的信息和第三⽅⽹站需要的⽤户权限展示给⽤户,并询问⽤户是否同意授权
  1. ⽤户点击「同意授权」按钮后,授权⽅⽹站将⻚⾯跳转回第三⽅⽹站,并传⼊Authorization code 作为⽤户认可的凭证
  1. 第三⽅⽹站将 Authorization code 发送回⾃⼰的服务器
  1. 服务器将 Authorization code 和⾃⼰的 client secret ⼀并发送给授权⽅的服务器,授权⽅服务器在验证通过后,返回 access token。OAuth 流程结束。
  1. 在上⾯的过程结束之后,第三⽅⽹站的服务器(或者有时客户端也会)就可以使⽤ access token 作为⽤户授权的令牌,向授权⽅⽹站发送请求来获取⽤户信息或操作⽤户账户。但这已经在 OAuth 流程之外。
例如掘金平台使用用 github 进行三方登录 授权过程如下:
notion image
拿到 access token 后,后端就拿到了 github 的授权,可以通过 access token 去访问github的获取用户头像,昵称等接口,然后通过这些用户信息在自己的服务器上注册并帮助用户登录。 一种不安全的做法是,把 access token 交给客户端自己去获取,这种方式就丧失了OAuth2 的安全性。 另一种不安全的是,客户端拿到 authorization code 后,直接去获取 access token,而不是交给后端获取。
 
💡
为什么 OAuth 要引⼊ Authorization code,并需要申请授权的第三⽅将Authorization code 发送回⾃⼰的服务器,再从服务器来获取 access token,⽽不是直接返回 access token ?这样复杂的流程意义何在? 为了安全。OAuth 不强制授权流程必须使⽤ HTTPS,因此需要保证当通信路径中存在窃听者时,依然具有⾜够⾼的安全性。
例如,第三⽅ App 通过微信登录的流程,也是⼀个 OAuth2 流程:
  1. 第三⽅ App 向腾讯申请第三⽅授权合作,拿到 client id 和 client secret
  1. ⽤户在使⽤第三⽅ App 时,点击「通过微信登录」,第三⽅ App 将使⽤微信 SDK 跳转到微信,并传⼊⾃⼰的 client id 作为⾃⼰的身份标识
  1. 微信通过和服务器交互,拿到第三⽅ App 的信息,并限制在界⾯中,然后询问⽤户是否同意授权该 App 使⽤微信来登录
  1. ⽤户点击「使⽤微信登录」后,微信和服务器交互将授权信息提交,然后跳转回第三⽅ App,并传⼊ Authorization code 作为⽤户认可的凭证
  1. 第三⽅ App 调⽤⾃⼰服务器的「微信登录」Api,并传⼊ Authorization code,然后等待服务器的响应
  1. 服务器在收到登录请求后,拿收到的 Authorization code 去向微信的第三⽅授权接⼝发送请求,将 Authorization code 和⾃⼰的 client secret ⼀起作为参数发送,微信在验证通过后,返回 access token
  1. 服务器在收到 access token 后,⽴即拿着 access token 去向微信的⽤户信息接⼝发送请求,微信验证通过后,返回⽤户信息
  1. 服务器在收到⽤户信息后,在⾃⼰的数据库中为⽤户创建⼀个账户,并使⽤从微信服务器拿来的⽤户信息填⼊⾃⼰的数据库,以及将⽤户的 ID 和⽤户的微信 ID 做关联
  1. ⽤户创建完成后,服务器向客户端的请求发送响应,传送回刚创建好的⽤户信息
  1. 客户端收到服务器响应,⽤户登录成功

在自家软件中使用 Bearer token

有的 App 会在 Api 的设计中,将登录和授权设计成类似 OAuth2 的过程,但简化掉 Authorization code 概念。即:登录接⼝请求成功时,会返回 access token,然后客户端在之后的请求中,就可以使⽤这个 access token 来当做 bearer token 进⾏⽤户操作了。

Refresh token

⽤法:access token 有失效时间,在它失效后,调⽤ refresh token 接⼝,传⼊ refresh_token 来获取新的 access token。 ⽬的:安全。当 access token 失窃,由于它有失效时间,因此坏⼈只有较短的时间来「做坏事」;同时,由于(在标准的 OAuth2 流程中)refresh token 永远只存在与第三⽅服务的服务器中,因此 refresh token ⼏乎没有失窃的⻛险。
 
HTTPSTCP/IP
Loading...
shuouyang
shuouyang
android开发 ReactNative开发 小程序开发
最新发布
AOSP 环境搭建
2025-3-29
View 绘制流程-源码解析
2025-3-12
HTTP
2025-3-4
JVM 虚拟机
2025-2-28
蓝牙-BLE-基础
2025-2-28
从 OkHttp 的原理来看 HTTP
2025-2-19
公告
🎉热点信息🎉
--- 1 ---
Jet Brains 推出新的跨平台支持 Kotlin MultiPlatform
--- 2 ---
新的小巧便捷的依赖注入框架 Koin
--- 3 ---
新一代 API 查询语言 GraphQL