OAuth 2 简洁说明书
技术分享
Apr 26, 2023
type
Post
status
Published
date
Apr 26, 2023
slug
oauth2-intro
summary
本文力求简洁明了且生动有趣地给你介绍 OAuth2,带你了解应用最广泛的认证授权规范
tags
OAuth
开发
category
技术分享
icon
password
Property
May 5, 2023 07:56 AM
 

角色

小王,需要一些资源,我们称之为需要访问资源的客户端(Client,简称 C)
小王,需要一些资源,我们称之为需要访问资源的客户端(Client,简称 C)
小玲,拥有很多资源,我们称其为资源主(Resource Owner,简称 RO)
小玲,拥有很多资源,我们称其为资源主(Resource Owner,简称 RO)
仓库,这是存放资源的地方,我们称其为资源服务器(Resource Server,简称 RS)
仓库,这是存放资源的地方,我们称其为资源服务器(Resource Server,简称 RS)
小张,登记员,我们称其为授权服务器(Authorization Server,简称 AS)
小张,登记员,我们称其为授权服务器(Authorization Server,简称 AS)

传统认证流程

小王和小玲经过友好协商达成协定,小玲线下递交钥匙给小王,(传统认证授权流程开始)小王拿着钥匙打开小玲的仓库,骑走自行车(传统认证授权流程结束)。
小王和小玲经过友好协商达成协定,小玲线下递交钥匙给小王,(传统认证授权流程开始)小王拿着钥匙打开小玲的仓库,骑走自行车(传统认证授权流程结束)。
上图是传统模式下的认证授权流程,场景是小王需要借用小玲的自行车,他们在协商好之后,小玲会把自己的仓库钥匙给小王,小王拿着钥匙到仓库打开门,骑走自行车,其中的认证授权体现在拿着钥匙打开门的过程,只有客户端拥有正确的密码或者权证,才能访问资源服务器中的资源。
传统的认证授权流程简单且符合直觉,客户(C)直接拿着资源主(RO)的认证或者密钥来仓库(RS)取货,这种模式流程清晰,实现起来也简单,已经被各种各样的应用系统广泛采用。那么这种流程会有什么问题呢?
  • 资源服务需要存储用户的密码(密钥,或者类似的内容)以识别客户端是不是有权限访问资源,而密码具有内在的弱安全性,使得此方案十分脆弱,容易被击破
  • 此方案授予了客户过于宽泛的权限,就像一旦有了钥匙,仓库里的东西也就予取予求了,而且资源主无法变更此授权的范围和时效
  • 资源主可能会将密码用于其他多个资源服务中,此时如果一个资源服务因被攻击泄露了密码,其他使用此密码的资源服务都会变得不安全,而且资源主不能针对特定客户取消授权,只能通过修改密码的方式取消所有跟此密码关联的客户的授权
  • 认证授权过程跟资源服务高耦合,就像如果拿着钥匙来的话,仓库里面必须要有机械锁才能打开,这样也就是让整个服务很难变更其认证授权模式,比如想让仓库使用指纹等
传统认证授权流程简洁且易于实现,但是不够安全和灵活,无法满足更进一步的认证授权的需求,OAuth 就应运而生了。

OAuth 流程

notion image
上图是 OAuth 的流程示意图,场景还是小王需要借用小玲的自行车,这个时候就需要分为以下三步来进行
  1. OAuth 流程的第一步是客户端请求授权,授权请求可以直接向资源所有者发出(如图所示),更好的选择是通过授权服务器作为中介间接发出,然后资源所有者给予授权许可,授权许可代表着资源所有者授权的凭证,它的类型会随着客户端请求类型的不同或者授权服务器支持的类型不同而不同。示例场景中,小王通过电子邮件联系小玲,请求其授权使用自行车,小玲回复一封邮件,确认小王的确是她的朋友并且可以使用自行车。小王是通过发邮件的方式请求授权,而且登记员小张可以读邮件,所以授权凭证就是这封来自小玲的回复邮件。按照 OAuth 的规范来说,小王更好的做法是通过小张作为中介来请求授权,由小张转发给小玲,小玲来确认授权。
  1. 第二步是客户端拿着授权凭证去授权服务器请求访问令牌,授权服务器校验凭证,如果是合法的,就签发访问令牌给客户端。示例场景中,小王拿着小玲的邮件来到了登记处找到小张,小张查看小玲的邮件并确认的确是小玲的签名,就登记并签发一张自行车提取单给了小王。
  1. 第三步是客户端凭访问令牌请求访问资源服务器中受保护的资源,资源服务器校验此令牌并根据结果接收或者拒绝客户端的访问请求。示例场景中,小王拿着小张签发的自行车提取单来到仓库,仓库门卫确认单据是有效的,就会让小王骑走自行车。
OAuth 通过引入额外的授权层并将客户端的角色与资源所有者的角色分离来解决这些问题,具体来说是下面三点
  • 引入额外的授权机制,分离认证和授权的过程。认证(Authentication)解决“你是谁”的问题,授权(Authorization)解决“你可以做什么”的问题,传统的流程中,并没有明确区分认证和授权,也就是说拿到钥匙的人,默认被认证为钥匙的主人,也就是资源所有者,就直接被授予了可以访问钥匙打开的仓库里所有资源的权限,而 OAuth 区别对待认证和授权,提供灵活配置的能力,让授权过程可以单独控制,授权的方式、范围、时效性等就有了独立变化的可能。
  • 抽象出客户端和资源所有者的角色,明确划分权限边界。传统流程中,一旦某个个体拥有了钥匙,对资源服务器来说,就是资源所有者,并不在意钥匙是不是属于当前持有者。OAuth 则明确抽象出了客户端和资源所有者角色,二者所拥有的权限边界就被显示界定了,客户端所有的操作都需要来自资源所有者的授权。
  • 授权脱离传统授权方式中所需的密码或者类似的介质,加固了安全性。

授权凭证的类型

授权凭证是资源所有者 RO 颁发给客户端的用来授权访问自己的资源的证明,也是客户端用来申请访问令牌(Access token)的凭证,就是示例中小玲回复的那份同意出借的邮件,它具有多种实现方式,支持不同类型的场景,它的形态跟客户端的请求方式和授权服务器支持的类型有关,下面简单介绍一下 OAuth 2 定义的两种常见授权凭证。

Authorization code 授权码

授权码是一种用于 Web 和移动 App 的常见方案,它的特点是资源所有者不会直接向客户端授权,而是给于一个授权码给客户端,客户端通过此授权码向授权服务器,然后授权服务器通过检验资源所有者的信息来完成认证,次过程中资源所有者的认证信息完全对客户端保密。
授权码流程示例如下:
  1. 客户端请求授权,授权服务器会提供一个认证页面的 URL 给客户端,客户端用浏览器打开这个URL 展示给资源所有者,比如一个照片美化的应用,想要访问用户存储在微博的照片,它必须先向微博的授权服务器注册自己,然后构建如下 URL 并用浏览器打开给微博的用户
    1. https://weibo-authorization-server.com/authorize? response_type=code &client_id=DVsKRVkI2dSdWp43ZJ38Ey5D &redirect_uri=https://www.meituxiuxiu.com/beautify-code.html &scope=photo+access &state=_YCV7ZXAizSZeKZt
      • response_type=code 告诉授权服务器此次授权正在使用授权码流程
      • client_id 是客户端向授权服务器注册的时候生成的唯一标识
      • redirect_uri 是向授权服务器说明当流程完成的时候应该跳转的地址
      • scope 客户端所需要的权限范围,用来展示给资源所有者
      • state 客户端生成的随机字符,用来防止 CSRF 攻击
  1. 资源所有者提供授权服务器所需的信息以证明自己拥有这些资源,在我们的例子中,用户需要在上面的 URL 所展示的页面中输入自己的微博用户名和密码,如果成功登录则会进入下一步,否则流程终止。
  1. 授权服务器展示客户端所需权限范围,并请求资源所有者授权,在例子中,微博认授权务器会展示 应用"美图秀秀"想要访问您的照片 这个提示,并给出授权和拒绝的按钮,用户如果点击授权,则继续下一流程,点击拒绝则终止流程。
  1. 授权服务器重定向到 redirect_uri,并携带 statecode 字段,客户端需要校对 state 参数,防止 CSRF 攻击。在例子中,如果客户端发现 state 不是 _YCV7ZXAizSZeKZt,则终止流程,如果符合,继续下一流程。
  1. 客户端根据上一步的授权码,也就是 code 字段,构建请求到授权服务器,用此授权码获取访问令牌,授权服务器返回访问令牌的信息给客户端,客户端即可使用此令牌访问受保护的资源,例子如下:
    1. POST https://weibo-authorization-server.com/token grant_type=authorization_code &client_id=DVsKRVkI2dSdWp43ZJ38Ey5D &client_secret=a2bFvVknKafddl7yLVjgzC8kOhTEhhf1gIaeqEdA2dbTnUg9 &redirect_uri=https://www.meituxiuxiu.com/beautify-token.html &code=D8QmIfUPnEowNK0vRwOXK_rQtZrVBi1GXOA1-wik3S-gNR9w 返回 { "token_type": "Bearer", "expires_in": 86400, "access_token": "9050Uk3Y0F_KAHrrKIwqtIItm7gulDmAlTo8QeMB_0Y0gxUJfrB43EUAptxskHahBTv2ddOC", "scope": "photo access", "refresh_token": "NgdHFFk4ouQHRTh9Bei1JK4l" }

Client Credentials 客户端证书

这种授权凭证一般是客户端为访问自己的资源申请的,而不是需要访问资源所有者的资源,所以流程相对比较简单,不需要资源所有者的认证和授权。
客户端证书流程如下:
  1. 客户端构建授权请求发送至授权服务器,需要包含自己的认证信息,以便授权服务器确认自己的身份,示例如下
    1. POST https://api.authorization-server.com/token grant_type=client_credentials& client_id=CLIENT_ID& client_secret=CLIENT_SECRET
      • grant_type=client_credentials向授权服务器说明自己进行的是 client_credentials 流程
      • client_id是客户端向授权服务器注册的时候生成的唯一标识
      • client_secret 是客户端向授权服务器注册的时候获得的一个密钥
  1. 授权服务器校验客户端的身份,并根据结果决定是否返回访问令牌,如果校验通过,则返回访问令牌给客户端,否则终止流程,返回示例如下
    1. { "token_type": "Bearer", "expires_in": 86400, "access_token": "9050Uk3Y0F_KAHrrKIwqtIItm7gulDmAlTo8QeMB_0Y0gxUJfrB43EUAptxskHahBTv2ddOC" }
 
当然,除了这两种常用的类型外,OAuth2.0 还提供了其他的授权类型,以及扩展机制来实现自定义的授权类型,这边不做过多介绍。

总结

当今数字化时代,用户对于安全性和隐私保护的需求越来越高,OAuth 2.0作为一种开放标准的授权协议,为用户和开发人员提供了更高的安全性、更好的用户体验和更广泛的应用程序支持,它不仅简化了授权过程,而且还能够为不同类型的应用提供不同级别的授权,灵活方便,还能根据需求定制开发特殊场景的解决方案,如果你有此类需求,选择它不会错。
 
  • OAuth
  • 开发
  • 手把手教会你快速部署 MySQL 8.0 InnoDB Cluster
    实践 Architecture decision record