本文将对oAuth 2.0协议做一个简单介绍。

本文主要内容翻译自文章:OAuth 2 Simplified。

本文分为如下几个部分:

  1. 角色:应用、api和用户
  2. 创建一个app
  3. 授权:获取访问token
  4. 认证
  5. 和oAuth 1.0的区别

1,角色:应用、api和用户

  • oAuth的客户。oAuth的“客户”是那些尝试访问用户账户信息的应用程序,而这个访问操作需要得到用户的同意才能完成。
  • 资源服务器(Resource Server,也叫做api server)。资源服务器提供了访问用户信息的api接口。
  • 授权服务器(Authorization Server):授权服务器提供了接口来让用户决定同意或者拒绝当前访问请求。很多情况下,Authorization Server和Resource Server是合在一个系统里的,虽然oAuth2.0允许它们独立开,甚至用不同的域名。
  • 用户:用户是他们自身账户信息的拥有者,对本次访问请求有决定权。

2,创建一个app

上文中提到oAuth的客户是应用程序。为了使用oAuth服务,应用程序需要先在oAuth服务上注册。注册时需要提供应用名称、网址、logo等信息。如果大家之前有使用过微信开放平台或者支付宝开放平台,对这个流程应该会深有体会。

2.1 重定向uri

oAuth服务只会把用户重定向到注册应用时提供的uri,以防止被攻击。所有的重定向uri都需要基于https协议,以防授权过程中token被截取。

对于原生app而言,重定向uri可以被定义成一个uri schema,类似于:demoapp://redirect这样。

2.2 client id & secret

应用程序注册好之后,oAuth服务会为其分配一个client id和一个client secret。client id是公共信息,用来构建登陆uri。client secret属于私密信息,需妥善保存。

3,授权:获取访问token

oAuth 2.0协议的第一步是获得用户授权。对于基于浏览器的应用或者移动端app,授权过程主要是通过向用户展示授权页面来完成的。

oAuth2.0提供了多种授权类型:

  • Authorization Code。主要适用于web应用和移动端应用。
  • 密码。适用于用户名密码登陆场景。
  • 客户端证书。适用于无需用户参与的场景。
  • 隐式方式。之前作为没有密钥情况下的推荐方式,现在已经被PKCE取代了。

接下来将详细讨论每种授权类型的应用场景。

3.1 web应用

web应用可能是我们在oAuth场景下碰到的最多的一种应用。web应用通常使用服务端程序语言编写,同时源代码不公开。这就意味着它能很好地保存注册应用时分配的client secret。

3.1.1 授权

为了获取用户授权,我们为用户构造一个登录连接:

https://authorization-server.com/auth?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=REDIRECT_URI&
scope=photos&
state=1234zyx

url参数说明如下:

  • response_type=code,表示服务器希望接收到授权码AUTHORIZATION_CODE
  • client_id ,注册应用时分配的client id
  • redirect_uri ,授权完成之后将请求重定向至该url,比如https://example-app.com/cb
  • scope ,用来说明希望访问用户账户信息的哪些部分
  • state,由当前应用生成的,用来做验证的一个随机字符串

用户访问上面的登陆链接,会看到类似下面这样的弹出页面:

图片引用自文章:https://aaronparecki.com/oauth-2-simplified/

如果用户点击“Allow”,授权服务会将当前访问重定向至redirect_uri,并在重定向url中附带授权码AUTHORIZATION_CODE和state随机字符串。

https://example-app.com/cb?code=AUTHORIZATION_CODE&state=1234zyx

url参数说明如下:

  • code。授权码AUTHORIZATION_CODE。
  • state。和登陆链接中的state字符串相同。

redirect_uri连接对应的处理逻辑,需要先看看授权服务在redirect_uri中附带的state字符串是否和登录连接中发出的state匹配。我们通常可以在session或者cookie中存储这个state字符串,然后在回调处理逻辑中比较是否一致。

3.1.2 获取access token

拿到AUTHORIZATION_CODE之后,我们就可以尝试获取access token了。我们可以通过向授权服务器发起一个post请求,用AUTHORIZATION_CODE换取access token:

POST https://api.authorization-server.com/token?grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

url参数说明如下:

  • grant_type=authorization_code,本流程用的授权类型是 authorization_code
  • code=AUTHORIZATION_CODE,持有的AUTHORIZATION_CODE
  • redirect_uri=REDIRECT_URI,重定向uri
  • client_id=CLIENT_ID,注册应用时分配的client id
  • client_secret=CLIENT_SECRET,注册应用时分配的client secret

授权服务器会回复一个access token及其过期时间:

{"access_token":"RsT5OjbzRn430zqMLgV3Ia","expires_in":3600
}

或者是一个错误:

{"error":"invalid_request"
}

3.2 Single-Page应用

Single-Page应用是指那些完全运行在浏览器中的应用。浏览器会下载这类应用的源代码并运行。这类应用没办法保证client secret的安全性,所以这类应用不能使用client secret。对于这类应用,授权流程会使用动态生成的client secret,而不是注册app时分配的。这个流程被称为PKCE扩展。

3.2.1 授权

首先创建一个长度为43到128位的随机字符串,这个字符串被称为code_verifier。比如:

5d2309e5bb73b864f989753887fe52f79ce5270395e25862da6940d5

用上面的随机字符串做SHA256运算,然后再做base64-encode运算,得到一个字符串,这个字符串被称为code_challenge。比如:

MChCW5vD-3h03HMGFZYskOSTir7II_MMTb8a9rJNhnI。

然后使用上面生成的字符串来创建登陆链接:

https://authorization-server.com/auth?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=REDIRECT_URI&
scope=photos&
state=1234zyx&
code_challenge=CODE_CHALLENGE&
code_challenge_method=S256

url参数说明如下:

  • response_type=code,表示希望接收到授权代码AUTHORIZATION_CODE
  • client_id,注册应用时分配的client id
  • redirect_uri ,授权完成之后将请求重定向至该url,比如https://example-app.com/cb
  • scope ,说明希望访问用户账户信息的哪些部分
  • state,由当前应用生成的,用来做验证的一个随机字符串
  • code_challenge,前面提到的code_challenge
  • code_challenge_method=S256,hash运算方法,这里使用的是sha256

用户访问上面的登陆链接,会看到类似下面这样的弹出页面:

图片引用自文章:https://aaronparecki.com/oauth-2-simplified/

如果用户点击“Allow”,授权服务会将当前访问重定向回redirect_uri,并在重定向uri中附带授权码和state随机字符串。

https://example-app.com/cb?code=AUTHORIZATION_CODE&state=1234zyx

url参数说明如下:

  • code。授权代码AUTHORIZATION_CODE。
  • state。和登陆链接中的state字符串相同。

redirect_uri连接对应的处理逻辑,需要先看看授权服务在redirect_uri中附带的state字符串是否和登录连接中发出的state匹配。我们通常可以在session或者cookie中存储这个state字符串,然后在回调处理逻辑中比较是否一致。

3.2.2 获取access token

拿到AUTHORIZATION_CODE之后,我们就可以尝试获取access token了。和web应用通过client secret获取access token方式不同,本场景使用上面生成的code_verifier来获取access token。我们构造如下的post请求来获取access token。

POST https://api.authorization-server.com/token?grant_type=authorization_code&code=AUTH_CODE_HERE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&code_verifier=CODE_VERIFIER

url参数说明如下:

  • grant_type=authorization_code,本流程用的授权类型是 authorization_code
  • code=AUTH_CODE_HERE,3.2.1节中获取到的AUTHORIZATION_CODE
  • redirect_uri=REDIRECT_URI,重定向uri
  • client_id=CLIENT_ID,注册应用时分配的client id
  • code_verifier=CODE_VERIFIER,上文中生成的code_verifier随机字符串

授权服务器会使用请求参数中的code_verifier,根据上面提到的code_challenge的生成流程来重新生成code_challenge。通过和登录请求中传递的code_challenge进行比较,就能确认当前请求的有效性。这个流程保证了,即使AUTHORIZATION_CODE可能会被恶意盗取,但盗取者没办法成功获得access token,因为他们没有client secret。

3.3 移动端app

就像基于浏览器的应用一样,移动端app也没有办法保证client secret的安全性。因此,移动端app也是使用基于PKCE的方式,无需client secret。

3.3.1 授权

对于移动端app,我们构建的登陆按钮会将用户重定向到手机上授权服务的原生app,或者授权服务提供的web页面。这个流程就好比当使用微信登陆或者支付宝做授权登陆时,唤起微信或者支付宝原生app。

3.3.1.1 使用授权服务的原生app

如果用户的手机上安装了facebook,我们可以将他重定向到下面的uri:

fbauth2://authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email&state=1234zyx

url参数说明如下:

  • response_type=code,表示服务器希望接收到AUTHORIZATION_CODE
  • client_id=CLIENT_ID,注册应用时分配的client id
  • redirect_uri=REDIRECT_URI ,重定向uri,比如: fb00000000://authorize
  • scope=email,说明希望访问用户账户信息的哪些部分
  • state=1234zyx,由当前应用生成的,用来做验证的一个随机字符串

对于要支持PKCE扩展的服务器来说,我们应该首先创建一个随机字符串作为code_verifier并存在本地,然后在上面的url中添加如下参数:

  • code_challenge,前面提到的code_challenge
  • code_challenge_method=S256,hash运算方法,这里使用的是sha256

3.3.1.2 使用web浏览器

如果授权服务本身不提供原生app。我们可以使用手机浏览器来访问授权uri。注意要使用手机浏览器而不是app上面的webview,以防止让用户进入钓鱼网站。

我们要么使用手机端浏览器,要么使用ios的SafariViewController,这个特性是ios 9才提供的。SafariViewController可以让用户看到地址栏的url地址,让他们知道他们正在访问的正确url地址。同时,这个特性也会和ios的safari浏览器共享cookie,并能防止app偷窥或者修改浏览器的内容,所以总体上是安全的。

然后我们就可以将用户重定向到下面的url来获取AUTHORIZATION_CODE了(如果授权服务支持PKCE,需要加上上面讨论过的code_challenge和code_challenge_method参数):

https://facebook.com/dialog/oauth?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email&state=1234zyx

url参数说明如下:

  • response_type=code,表示服务器希望接收到AUTHORIZATION_CODE
  • client_id=CLIENT_ID,注册应用时分配的client id
  • redirect_uri=REDIRECT_URI,重定向uri,比如: fb00000000://authorize
  • scope=email,说明希望访问用户账户信息的哪些部分
  • state=1234zyx,由当前应用生成的,用来做验证的一个随机字符串

用户会看到下面的弹出页面:

图片引用自文章:https://aaronparecki.com/oauth-2-simplified/

3.3.2 获取access token

用户点击“Okay”后,会通过下面的url重定向到你的应用:

fb00000000://authorize?code=AUTHORIZATION_CODE&state=1234zyx

你的移动端应用需要先验证下state字段的正确性,然后就可以用AUTHORIZATION_CODE去获取access token了。

access token的获取过程和"3.1 web应用"中讨论的流程类似,只是请求中不会包含client_secret。如果授权服务支持PKCE,需要加上上面讨论过的code_challenge和code_challenge_method参数。

POST https://api.authorization-server.com/tokengrant_type=authorization_code&code=AUTH_CODE_HERE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&code_verifier=VERIFIER_STRING

url参数说明如下:

  • grant_type=authorization_code,本流程用的授权类型是 authorization_code
  • code=AUTH_CODE_HERE,上一个步骤中获取到的AUTHORIZATION_CODE
  • redirect_uri=REDIRECT_URI,重定向uri
  • client_id=CLIENT_ID,注册应用时分配的client id
  • code_verifier=VERIFIER_STRING,创建code_challenge使用的随机字符串

授权服务器会验证上面的请求并返回acces token。

如果授权服务器支持PKCE,则会使用 code_verifier来重新生成code_challenge并和登录请求中的code_challenge进行对比,以达到无需使用client secret也能完成授权的过程。

3.4 其他授权类型

3.4.1 密码

oAuth2 也提供密码授权类型,通过用户名和密码来获取access token。因为这个过程涉及到让app程序获取用户密码,这种模式只能被用在这个app是由授权服务提供的情况下。比如,twitter app可以用这种方式来登陆移动端或者pc应用。

为了使用密码授权方式,通过如下的post请求即可:

POST https://api.authorization-server.com/tokengrant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID

url参数说明如下:

  • grant_type=password,本流程使用password授权类型
  • username=USERNAME,用户名
  • password=PASSWORD,密码
  • client_id=CLIENT_ID,首次注册应用时分配的client id

授权服务会返回和其他授权类型一样的access token。

3.4.2 应用访问

在某些情况下,应用可能需要oAuth授权服务,这些访问不是针对某个用户的,而是应用自身的。比如,当应用要更新url或者icon,或者获取所有用户的统计信息,这类请求其实和单个用户无关。oAuth提供了client_credentials这种授权类型来处理这种情况。

为了使用client_credentials授权类型,通过如下post请求即可:

POST https://api.authorization-server.com/tokengrant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

授权服务返回的结果中就会包含access token。

4, 创建已授权请求

所有授权类型的结果就是获得了一个access token。

既然已经拿到了access token,我们就能轻松使用curl工具来构建一个授权过的api 请求了:

curl -H "Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia"  https://api.authorization-server.com/1/me

记住,一定要使用https协议,只有https才能防止请求被劫持或者被修改。

5, 和oAuth1.0的区别

oAuth1.0主要是基于已经存在的协议,比如Flickr的 "FlickrAuth"和Google的 "AuthSub"而设计的。oAuth2.0是一个完全重新设计的协议,和oAuth1.0不兼容。

5.1 认证和签名

oAuth1.0协议失败的主因,可以归结于其对加密的要求。对于习惯了使用用户名密码的程序员来说,要使用oAuth1.0意味着需要安装和配置一些加密方面的库来使用这个协议。在传输过程中,用户名和密码等私密信息被加密后传输。

对于oAuth2.0来说,我们使用access token来代替用户名和密码,避免使用加密算法。

5.2 用户体验

oAuth2.0主要分为两步:

  1. 获取用户授权,授权的结果就是当前应用得到了access token。
  2. 使用access token来访问资源。

oAuth1.0将不同类型的应用的授权流程合并成一个流程,增加了流程的复杂性,而且用户体验非常不好。

oAuth2.0则为不同类型的应用提供不同的授权类型,增加了可支持的应用类型的同时(对于新的应用类型,可以新增授权类型),大大提升了用户体验。

5.3 oAuth2.0具有更灵活的token撤回机制

oAuth 1.0的access token通常具有很长的有效期,而且这个有效期可能是无限长。负责任的api接口提供方,通常可以让用户看到他们曾经授权过哪些应用来获取他们的账户信息,同时可以轻易撤回这些授权。

oAuth2.0通过分配一个短生命周期的acces token和一个长生命周期的refresh token来解决这个问题,避免某个access token长时间有效。

5.4 角色分离

oAuth2.0允许API Server和Authorization Server分离。

  • Authorization Server可以只是负责获得用户的授权并向应用分配access token。授权服务器需要知道应用的client_id和client_secret。
  • API Server只需要能够识别access token即可。

API Server和Authorization Server可以独立部署,独立扩容。比如Google’s OAuth 2.0 使用 “accounts.google.com” 作为Authorization Server,使用 “www.gooogleapis.com” 作为API Server。

参考:

1,https://www.oauth.com/oauth2-servers/differences-between-oauth-1-2/

2,https://aaronparecki.com/oauth-2-simplified/

oauth2中用户的信息如何动态获取和存储_oAuth2.0 简介相关推荐

  1. android动态获取地理位置权限,Android6.0获取GPS定位和获取位置权限和位置信息的方法...

    1.添加权限--6.0之后要动态获取,下面会说 2.直接上代码,不多说,代码中注释很详细. private static final int BAIDU_READ_PHONE_STATE = 100; ...

  2. android 动态获取全县_android 6.0之后动态获取权限

    1. 概述 Android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再需要询问用户.在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在 ...

  3. JS本地存储加载渲染页面信息、动态更新本地存储数据

    本地存储数据加载到页面: 从本地存储中获取数据,并由字符串基础类型转换为对象类型(存储至堆内存中) 初始化变量data 为空数组(变量data存储在栈内存中) 将获取的数据赋值给变量data (实质为 ...

  4. 实用知识点梳理:网络操作系统、HTTPS、交换机中用户权限、路由器与集线器功能、HTTP2.0特性

    网络操作系统 网络操作系统的基本任务: 屏蔽本地资源与网络资源之间的差异: 为用户提供基本的网络服务功能: 管理网络系统的共享资源: 提供网络系统的安全服务. HTTPS 在HTTP跟TCP中间多了一 ...

  5. web项目中填写sql信息自动动态生成报表功能(springboot)

    (一)大概 背景: 需求就是设计一个自定义报表功能,当需要新报表时,能够快速的构建. 经过初步的构思,有至少三种方式可以实现: 构建demo代码,一个报表对应编写一套代码,不过可以将重复代码提取,尽可 ...

  6. java中bpmn流程图_Activiti如何动态获取流程图过程详解

    本文中使用的activiti版本是5.22.0 一.绘图原理 activiti中提供了一个可以用来绘制流程图的类DefaultProcessDiagramGenerator,这个类在5.22.0及以上 ...

  7. linux系统中用户账户信息保存在,【填空题】Linux系统中,除密码外的用户账户信息保存在 配置文件中...

    参考答案如下 填空题非竞争性拮抗药 正当防卫中的不法侵害已经开始,系统信息下列说法中错误的是( ) 患者,中除账户配置文男性,中除账户配置文47岁.连日来在炼钢炉旁工作,虽感疲乏,但仍坚持操作.今日上 ...

  8. 将Excel导入DataGridView 中的select * from [Sheet1$]中[ ]里面表单名的动态获取

    Sheet1$是Excel默认的第一个表名,如果改动:select * from [Sheet1$]"将查询失败,因此应根据选择自动获取excel表名: 1 OpenFileDialog o ...

  9. 在asp.net如何取得ActiveDirectory域中用户的信息,比如工号,邮件地址等等

    using System; using System.Drawing; using System.Collections; using System.ComponentModel; using Sys ...

最新文章

  1. java kafka 集群消费_kafka集群搭建和使用Java写kafka生产者消费者
  2. 【Network Security!】xrdp+vnc4server+xfce4远程管理Ubuntu服务器桌面
  3. ASP.NET完整打包卸载更新攻略(By Installshield 2010)【转】
  4. GetClientRect()和GetWindowRect()
  5. 551. 学生出勤记录
  6. 说说 Android 的 Material Design 设计(四)——卡片式布局
  7. 51 -算法 -LeetCode 53最大子序和 动态规划
  8. python批量运行cmd_python 批量ssh并执行命令
  9. java底层模型_Java I/O模型及其底层原理,夯实你的开发基础
  10. 字符编码 ASCII,Unicode和UTF-8的关系
  11. h5直接分享的实现方案
  12. windows 7 与linux 双系统 安装
  13. 没解决:MMC不能打开文件MSC可能是由于文件不存在,不是一个MMC控制台,或者用后来的MMC版本创建。也可能你没有访问此文件的足够权限
  14. 【互动出版网】央视热播BBC纪录片同名图书买二赠一活动
  15. windows 安装 telnet 工具
  16. 国家海洋局事业单位公开招聘考试大纲2016
  17. python求因子个数_python怎么求因数
  18. Linux中的Cat命令–如何使用Cat或Touch创建文本文件
  19. 【精】HDFS Balancer原理、参数详解
  20. “红山开源”创新论坛 | ChinaOSC

热门文章

  1. pybind11 入门
  2. QTableView表格视图的列宽设置
  3. windows 关闭端口被占用脚本
  4. makefile多目录多文件
  5. 金猪钱罐——青龙羊毛
  6. PMP-【第1章 引论】-2020-12-07(18页-24页)
  7. 必须重启计算机才能关闭用户控制,Win10如何彻底关闭用户帐户控制?Win10关闭用户控制方法...
  8. 服务器怎么打开数据库文件夹,服务器怎么打开数据库文件夹下
  9. glide源码中包含了那种设计模式_推荐一个好用的拍照选图库,致敬Glide
  10. python templates_详解Python的Django框架中的templates设置