登录与授权

登录和授权的区别

  • 登录:身份认证,即确认“你是你”的过程。
  • 授权:由身份或持有的令牌确认享有某些权限(例如获取⽤户信息)。登录过程实质上的⽬的也是为了确认权限。

       因此,在实际的应⽤中,多数场景下的“登录”和“授权”界限是模糊的。

Cookie

起源

       “购物⻋”功能的需求,由 Netscape 浏览器开发团队打造。

⼯作机制

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

       图例:

Cookie工作机制1

       如上图在购物车添加一个苹果,访问“cart”购物车的“path”,用“post”传入一个数据“apple = 1”,表示购物车增加一个苹果。

Cookie工作机制2

       服务器处理完成,返回信息,同时附加一个 header—“Set-Cookie”(Cookie 是客户端给服务端用的,Set-Cookie是服务端给客户端用的),要求客户端保存cart = “apple = 1”

Cookie工作机制3

       客户端按域(此处是 shop.com)保存该 Cookie ,原封不动地将 cart = “apple = 1”保存下来。当再次访问指定的域时,Cookie 内容会自动附加出去,这是由浏览器来实现的,网站开发者或者用户不必关心。

Cookie工作机制4

       下次再向购物车添加香蕉时,只需要发送 banana = 1 ,同时将 Cookie 附加过去(浏览器执行的)。通过 psot 的 body 告诉服务器需要增加一个香蕉 ,通过 Cookie 自动告诉服务器已经增加了一个苹果。

Cookie工作机制5

       服务器这边已经确定,现在购物车里面一个苹果一个香蕉。

Cookie工作机制6

       客户端自动更新 Cookie 。整个过程服务器没有记录任何数据。

作用

会话管理:登录状态、购物车等

使用Cookie管理登录状态1

       向服务器发送登录请求,将用户名和密码添加。

使用Cookie管理登录状态2

       服务器确认 a 登录了,并创建一个会话,表示服务端在和某个用户代理(User-Agent)在通信,对方可能是一个登录或未登录状态。例如服务器记录下会话信息:session:id = 123。并将会话信息返回给客户端,表示和客户端在交互。

使用Cookie管理登录状态3

       客户端将 sessionid = 123 记录下来。

使用Cookie管理登录状态4

       客户端再去访问时,会将 sessionid = 123 带过去。

使用Cookie管理登录状态5

       服务器收到后,会对照是否有该会话,查到有 session:id = 123 ,并且处于登录状态,于是将用户信息返回。

使用Cookie管理登录状态6

       Cookie 是可以有多个的,像这样客户端有两个 Cookie :sessionid = 123 和 cart = “apple = 1”,二者互不干扰,分别管理登录和购物车。但管理登录服务器还是需要保存会话的。

Cookie管理用户偏好1

Cookie管理用户偏好2

Cookie管理用户偏好3

Cookie管理用户偏好4

Cookie管理用户偏好5

Cookie管理用户偏好6

       假设 shop.com 有多个主题,客户端发出请求,服务端返回 client_id=123 。客户端特意发送请求改变主题为蓝色,服务器正常返回,并且记下了 client_id=123 的客户端的主题为蓝色。HTTP 是无状态的,下次客户端再访问另外一个页面 other_page ,client_id=123 自动附加,服务器根据 client_id=123 便知道需要蓝色主题了。

Tracking:分析用户行为

使用Cookie追踪用户行为1

       客户端向服务器发送信息。

使用Cookie追踪用户行为2

       之前的例子中,将服务器返回的 body 省略掉了,此处不能省略,因为 body 是做追踪的主要部分。可以看到图片链接中,增加了和图片地址本身无关的信息:“from=shop.com”,“3rd-party.com”这个网站就是帮助记录用户行踪的网站。追踪用户行为会有一个统一的网站,该网站记录用户去各个站点的信息。该图片链接在用户打开网页之后,会自动显示一张图片,图片会附加“from=shop.com”信息,该信息与图片显示无关。假设如果不是在“shop.com”打开该图片,而是在“taobao.com”,那么图片后面追加的信息则是“from=taobao.com”,二者显示的是同样的图片,但是对于第三方记录网站来说当前用户的来源不一样(“shop.com”还是“taobao.com”)。

使用Cookie追踪用户行为3

       客户端记录下 Cookie :client_id=123 ,向第三方(3rd-party.com)发送请求获取图片,第三方会记录 client_id=123 的用户来自 shop.com 。

使用Cookie追踪用户行为4

       第三方将图片显示给用户。

使用Cookie追踪用户行为5

       “client_id=abc” 是针对第三方网站的 id ,与 “client_id=123”没有关系,名字(client_id)是可以不一样的。“shop.com:client_id=123” 是用来管理用户的,而“3rd-party.com:client_id=abc”是用来记录用户行踪的。如果该用户再去“taobao.com”,该网站同样做了相同的第三方统计,在显示图片时,第三方网站会知道该用户之前去过“shop.com”,现在来了“taobao.com”,便会记录下这两个网站。这个时候对用户就有一定的画像了,用户去了两个网站。随着用户去的网站多,画像越详细,便有利于推广告。

XSS (Cross-site scripting)

       跨站脚本攻击。即使⽤ JavaScript 拿到浏览器的
Cookie 之后,发送到⾃⼰的⽹站,以这种⽅式来盗取⽤户 Cookie。

       应对⽅式: Server 在发送
Cookie 时,敏感的 Cookie 加上 HttpOnly ,这个 Cookie 只能⽤于 HTTP 请求,不能被 JavaScript 调⽤。它可以防⽌本地代码滥⽤ Cookie。

XSRF (Cross-site request forgery)

       跨站请求伪造。即在⽤户不知情的情况下访问已经保存了 Cookie 的⽹站,以此来越权操作⽤户账户(例如盗取⽤户资⾦)。

       应对⽅式主要是从服务器安全⻆度考虑,如 Referer 校验。

Authorization

       两种主流⽅式: Basic 和 Bearer 。

Basic

       格式: Authorization: Basic <username:password(Base64ed)>

       示例如下(比如用户名和密码分别为 wy521angel:123456,Base64 转换后为 d3k1MjFhbmdlbDoxMjM0NTY= ):

1
2
3
4
5
get /user http:/1.1
host: XXXXX.XXX
Authorization: Basic d3k1MjFhbmdlbDoxMjM0NTY=

http:/1.1 200 OK

       “Authorization: Basic d3k1MjFhbmdlbDoxMjM0NTY=”这个就是认证信息,用在 header 中,如果数据对了,就可以获取到用户信息。为了安全,需要使用 Https 来传输。

Bearer

       格式: Authorization: Bearer <bearer token>

       bearer token 的获取⽅式:通过 OAuth2 的授权流程。

OAuth2 的流程图例:

OAuth2 的流程图例1

OAuth2 的流程图例2

OAuth2 的流程图例3

OAuth2 的流程图例4

OAuth2 的流程图例5

  1. 第三⽅⽹站向授权⽅⽹站申请第三⽅授权合作,拿到 client id 和 client secret ;
  2. ⽤户在使⽤第三⽅⽹站时,点击「通过 XX (如 GitHub) 授权」按钮,第三⽅⽹站将⻚⾯跳转到授权⽅⽹站,并传⼊ client id 作为⾃⼰的身份标识;
  3. 授权⽅⽹站根据 client id ,将第三⽅⽹站的信息和第三⽅⽹站需要的⽤户权限展示给⽤户,并询问⽤户是否同意授权;
  4. ⽤户点击「同意授权」按钮后,授权⽅⽹站将⻚⾯跳转回第三⽅⽹站,并传⼊ Authorization code 作为⽤户认可的凭证;
  5. 第三⽅⽹站将 Authorization code 发送回⾃⼰的服务器;
  6. 服务器将 Authorization code 和⾃⼰的 client secret ⼀并发送给授权⽅的服务器,授权⽅
    服务器在验证通过后,返回 access token, OAuth 流程结束;
  7. 在上⾯的过程结束之后,第三⽅⽹站的服务器(或者有时客户端也会)就可以使⽤ access
    token 作为⽤户授权的令牌,向授权⽅⽹站发送请求来获取⽤户信息或操作⽤户账户。但这
    已经在 OAuth 流程之外。

       如下图所示,Server 有时会把 access token 发还给客户端,这个不是不允许的,只不过这会对安全有一定的影响:

OAuth2流程思考1

       如下图所示,这样请求也是允许的,很多公司都这样使用,只是它可能不太具有 OAuth2 的安全性:

OAuth2流程思考2

1
2
3
为什么 OAuth 要引⼊ Authorization code,并需要申请授权的第三⽅将 Authorization code 发送回⾃⼰的服务器,再从服务器来获取 access token,⽽不是直接返回 access token ?这样复杂的流程意义何在?

为了安全。 OAuth 不强制授权流程必须使⽤ HTTPS,因此需要保证当通信路径中存在窃听者时,依然具有⾜够⾼的安全性。
1
2
第三方登录与第三方授权中的“第三方”:
拿用户、掘金社区和 Github 举例,用户通过 Github 账号登录掘金,本来是用户和 Github 之间的信息,现在分享给掘金社区,则授权中的“第三方”是掘金;而通过 Github 账号登录掘金,登录的是掘金社区,利用了 Github ,登录的“第三方”是 Github 。

微信登录:

       第三⽅ App 通过微信登录的流程,也是⼀个 OAuth2 流程:

  1. 第三⽅ App 向腾讯申请第三⽅授权合作,拿到 client id 和 client secret ;
  2. ⽤户在使⽤第三⽅ App 时,点击「通过微信登录」,第三⽅ App 将使⽤微信 SDK 跳转到
    微信,并传⼊⾃⼰的 client id 作为⾃⼰的身份标识;
  3. 微信通过和服务器交互,拿到第三⽅ App 的信息,并限制在界⾯中,然后询问⽤户是否同
    意授权该 App 使⽤微信来登录;
  4. ⽤户点击「使⽤微信登录」后,微信和服务器交互将授权信息提交,然后跳转回第三⽅
    App,并传⼊ Authorization code 作为⽤户认可的凭证;
  5. 第三⽅ App 调⽤⾃⼰服务器的「微信登录」 Api,并传⼊ Authorization code,然后等待
    服务器的响应;
  6. 服务器在收到登录请求后,拿收到的 Authorization code 去向微信的第三⽅授权接⼝发送
    请求,将 Authorization code 和⾃⼰的 client secret ⼀起作为参数发送,微信在验证通过
    后,返回 access token ;
  7. 服务器在收到 access token 后,⽴即拿着 access token 去向微信的⽤户信息接⼝发送请
    求,微信验证通过后,返回⽤户信息;
  8. 服务器在收到⽤户信息后,在⾃⼰的数据库中为⽤户创建⼀个账户,并使⽤从微信服务器
    拿来的⽤户信息填⼊⾃⼰的数据库,以及将⽤户的 ID 和⽤户的微信 ID 做关联;
  9. ⽤户创建完成后,服务器向客户端的请求发送响应,传送回刚创建好的⽤户信息;
  10. 客户端收到服务器响应,⽤户登录成功。

在⾃家 App 中使⽤ Bearer token

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

Refresh token

1
2
3
4
5
6
{
"token_type": "Bearer",
"access_token": "xxxxx",
"refresh_token": "xxxxx",
"expires_time": "xxxxx"
}
  • ⽤法: access token 有失效时间,在它失效后,调⽤ refresh token 接⼝,传⼊ refresh_token 来获取新的 access token。
  • ⽬的:安全。当 access token 失窃,由于它有失效时间,因此坏⼈只有较短的时间来“做坏
    事”;同时,由于(在标准的 OAuth2 流程中) refresh token 永远只存在与第三⽅服务的服务
    器中,因此 refresh token ⼏乎没有失窃的⻛险。

参考资料:
腾讯课堂 HenCoder

Fork me on GitHub