OAuth 2.0 的探险之旅

f96099cc2bf87ec0cf566b85b027039d.png

前言

OAuth 2.0 全称是 Open Authorization 2.0, 是用于授权(authorization)的行业标准协议。OAuth 2.0 专注于客户端开发人员的简单性,同时为 Web 应用程序、桌面应用程序、移动设备应用等提供了特定的授权流程。它在2012年取代了 OAuth 1.0, 并且 OAuth 2.0 协议不向后兼容 OAuth 1.0。

需要注意的是,OAuth 2.0 是一个授权(authorization)协议,而不是身份验证(authentication )协议。

Roles 角色

首先还需要了解一些概念, 因为整个OAuth授权流程都是围绕这些抽象的概念展开的, 角色是 OAuth2.0 授权框架核心规范的一部分, OAuth 定义了以下4种角色

•Resource Owner
资源所有者, 这里通常是拥有资源权限的用户或者系统。
•Client
客户端应用, 它可以通过访问令牌(Token)访问受保护资源, 可以是Web浏览器上的网站也可以是桌面应用或者手机App。
•Authorization Server
授权服务器, 在经过用户的授权后, 向客户端应用发放访问令牌(Access Token)。
•Resource Server
资源服务器, 存放受保护资源的服务器, 接受来自客户端(Client)请求的有效访问令牌(Access Token), 然后返回对应的资源。

Client Types 客户端类型

OAuth 2.0 核心规范定义了两种客户端类型, confidential 机密的, 和 public 公开的, 区分这两种类型的方法是, 判断这个客户端是否有能力维护自己的机密性凭据(password, client_secret)。

•confidential 对于一个普通的web站点来说,虽然用户可以访问到前端页面, 但是数据都来自服务器的后端api服务, 前端只是获取授权码code, 通过 code 换取access_token 这一步是在后端的api完成的, 由于是内部的服务器, 客户端有能力维护密码或者密钥信息, 这种是机密的的客户端。
•public 对于一个没有后端的纯前端应用来说(比如SPA), 数据的展示和操作都是在前端完成的, 包括获取令牌和操作令牌, 把一个客户端密码或者密钥放在纯前端应用是不安全的, 这种是公开的客户端。

Client Authentication 客户端身份认证

前面已经说过了, OAuth 2.0 是授权协议, 那为什么还要对 OAuth 2.0 客户端进行身份验证呢?身份验证和授权有什么区别?简单说身份验证确认用户是否是本人, 而授权则是授予用户访问资源的权限, 授权的前提条件一定是要先通过身份认证, 而且接下来的内容中, 也有用到了身份认证, 为了方便理解, 所以对认证做了简单的介绍。

授权服务器对客户端进行身份验证可以保证把令牌颁发给了合法的客户端, 但是认证其实已经超出了 OAuth2.0 的协议范围, 在 [RFC 6749] 中也只是简单介绍了以下2种认证方式:

第一种是使用 HTTP Basic [RFC2617] 中定义的身份验证方案进行身份认证, 这种方式叫 client_secret_basic, 首先需要对username,password 或者 client_id, client_secret 用冒号进行拼接。

{username}:{password} 或者 {client_id}:{client_secret} 就像这样 admin:123456
然后对字符串进行Base64编码, 然后设置为请求Header中的Authorization, 注意前面要拼接一个Basic和空格, 如下

POST /token HTTP/1.1Host: www.authorization-server.com Authorization: Basic YWRtaW46MTIzNDU2Content-Type: application/x-www-form-urlencoded

第二种方式就更简单粗暴了, 直接在请求体中添加 client_id 和 client_secret 参数, 如下

POST /token HTTP/1.1Host: www.authorization-server.com Content-Type: application/x-www-form-urlencodedgrant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA&client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw

Protocol Flow 协议流程

1cbdf5b6c428775974f00d259e38c02c.png

上图是抽象的授权协议流程, 也展示了4种角色(Role)之间的交互, 具体的过程如下

(A) 客户端向资源所有者(用户)发起授权请求, 资源所有者选择授予权限或者取消, 这个过程中, 授权服务器充当中介的角色, user ---> authorization server ----> client.
(B) 客户端收到授权许可(code),这是一个代表资源所有者授权的凭证。
(C) 客户端通过授权许可(code)向授权服务器发起请求, 并期望获取一个访问令牌(access token)。
(D) 授权服务器对客户端进行身份验证并验证授权许可,如果有效,则颁发访问令牌(access token)并返回。
(E) 客户端通过访问令牌向资源服务器请求受保护的资源。
(F) 资源服务器验证访问令牌, 如果有效, 则返回相应的资源。

Access Token 访问令牌

access token 是一个用来访问受保护资源的凭证, 它是由授权服务器(Authorization Server)颁发给客户端(Client)的, 通常是字符串形式, access token 拥有特定的访问范围(scope), 并且有时间限制, 访问令牌可以有不同的格式、结构, 这点并没有限制。

Refresh Token 刷新令牌

refresh token是一个用来获取access token的凭证, 同样它是由授权服务器(Authorization Server)颁发给客户端(Client)的, 刷新令牌的时效性比访问令牌要长, 当访问令牌过期的时候, 可以直接用刷新令牌去授权服务器获取新的访问令牌, 而无需重新登录。和访问令牌不同的是, 授权服务器颁发访问令牌是必须的, 而颁发刷新令牌则是可选的, 并且访问令牌还会和资源服务器交互, 而刷新令牌只和授权服务器交互。

刷新令牌的设计非常巧妙, 它是用户体验和安全两方面取舍的一个平衡。

797be93acdfeff4a88567a62a04f4508.png

(A) 客户端向授权服务器发起请求, 并提供授权许可。
(B) 授权服务器对客户端进行身份验证并验证授权许可,如果有效,则颁发访问令牌和刷新令牌。
(C) 客户端请求受保护资源并提供访问令牌。
(D) 资源服务器验证这个访问令牌,如果有效, 返回相应的内容。
(E) 重复步骤 (C) 和 (D),直到访问令牌过期。如果客户端知道了访问令牌已经过期,它跳到步骤(G), 如果不知道, 继续向资源服务器发起请求。
(F) 由于访问令牌无效,资源服务器返回无效的令牌错误。
(G) 客户端发起获取刷新令牌的请求, 同时要带上当前的刷新令牌。
(H) 授权服务器对客户端进行认证并验证刷新令牌,如果有效,则发出新的访问令牌和一个可选的新的刷新令牌。

Authorization Grant 授权许可

授权许可是一个资源所有者授权的凭证, 客户端通过它去获取访问令牌(access token), OAuth 2.0定义了以下四种许可模式。

•Authorization Code 授权码•Implicit 隐式•Resource Owner Password Credentials 密码•Client Credentials 客户端凭证

Authorization Code Grant 授权码模式

授权码模式是最常用的一种授权许可模式, 也是最经典的一种, 这种模式可以获取到访问令牌和刷新令牌。还有一个特点是, 授权码模式是基于Web重定向的流程。

e7771bee7b65da450079bbac219c96bb.png

(A) 客户端提供一个授权链接, 引导用户点击跳转到授权服务的 /authorize 端点, 如下

https://www.authorization-server.com/oauth2/authorize?response_type=code&client_id=s6BhdRkqt3&scope=user&state=8b815ab1d177f5c8e &redirect_uri=https://www.client.com/callback

参数说明如下:

•response_type:必选项, 表示响应类型,此处的值固定为"code"•client_id:必选项, 客户端的身份标识•redirect_uri 可选项, 经过用户允许授权后, 授权服务器跳转到客户端的回调地址•scope 可选项, 希望用户同意授权的权限范围•state 可选项, 推荐使用, 客户端可以维护一个在请求和回调之间的状态, 授权服务器重定向到回调地址时, 会带上这个参数, state 可以防止跨站点请求伪造-CSRF攻击。

(B) 授权服务器提供授权页面, 用户选择同意授权或者拒绝来自客户端的请求, 如下所示

d734713ba64b37097a1f52369946afbd.png

(C) 假如用户同意了授权, 授权服务器会通过url重定向到客户端的回调地址, 并且会带上一个授权码 code 和 state 参数(如果之前客户端的请求中传递了state参数的话)

https://www.client.com/callback?code=d8c2afe6ecca004eb4bd7024&state=8b815ab1d177f5c8e

(D) 现在已经拿到了授权码 code 并获得了用户的授权, 接下来需要用 code 来换取 访问令牌 access_token, 可以向授权服务的 /token 端点发送 POST 请求。

POST /token HTTP/1.1 Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JWContent-Type: application/x-www-form-urlencodedhttps://www.authorization-server.com/oauth2/token?grant_type=authorization_code&code=d8c2afe6ecca004eb4bd7024&redirect_uri=https://www.client.com/callback

参数说明如下:

•grant_type: 必选项,表示授权类型, 此处的值固定为"authorization_code"
•code: 必选项,授权码, 这是上一步从授权服务器传给回调地址(redirect_uri)的参数
•redirect_uri: 必选项, 客户端的回调地址, 注意要和(A)步骤中的 redirect_uri 一致。
•client_id: 必选项,客户端的身份标识

注意, 上面使用了 Http Basic 身份认证(Authorization: Basic ...), 在本文的 "客户端身份认证" 部分有介绍, 主要是为了验证 Client 的合法性。

通过code换取access_token 步骤中,还有一种比较常见的身份验证做法是, 直接在请求体中传入 client_id, client_secret, 如下:

POST /token HTTP/1.1  Content-Type: application/x-www-form-urlencodedhttps://www.authorization-server.com/oauth2/token?grant_type=authorization_code&code=d8c2afe6ecca004eb4bd7024&client_id=s6BhdRkqt3&client_secret=ecca004eb4bd7024c2afe6ecc&redirect_uri=https://www.client.com/callback

(E) 授权服务器对 client,code 验证通过后, 会返回 access_token 和一个可选的 refresh_token, 如下:

HTTP/1.1 200 OKContent-Type: application/json;charset=UTF-8Cache-Control: no-storePragma: no-cache{  "access_token":"2YotnFZFEjr1zCsicMWpAA",  "token_type":"bearer",  "expires_in":3600,  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" }

参数介绍:

•access_token: 必选项,访问令牌
•token_type: 令牌类型, 通常是 Bearer [RFC6750], 访问受保护资源需要在请求头设置 (Authorization:Bearer ...)
•expires_in: 访问令牌的有效期, 以秒为单位
•refresh_token:可选的刷新令牌

(F) 客户端使用 access_token 向资源服务器发起请求
(G) 资源服务器验证 access_token, 验证通过后, 返回受保护的资源

这里有一个问题是, 文章上面说 access_token 只是一个字符串, 那么资源服务器如何来验证该令牌?在 OAuth 2.0 核心协议中, 关于这点并没有提及。

访问令牌主要分为两种, 一种是没有意义的随机字符串, 比如 2YotnFZFEjr1zCsicMWpAA, 这种情况客户端本身是不能鉴别令牌是否有效, 只能去授权服务器发起请求来验证该令牌, 这种安全性高,但性能差, 可以参考 RFC 7662.

第二种就是很常见的 JWT 令牌, 可以参考 RFC 7519, 令牌本身就包含了一些用户信息, 资源服务器可以通过加密算法和签名验证令牌是否有效, 而且不需要和授权服务器进行交互, 但是缺点是, 如果令牌在到期前被撤销, 资源服务器是没办法知道的。

Implicit Grant 隐式授权模式

38374939fdf9a2f3e837de9ca4c4592d.png

上面是隐式授权的流程图, 它和授权码模式很像, 区别在于, 授权码模式是先拿到code,然后再换取access_token, 而隐式授权只用一次请求就拿到了access_token, 通过url参数的形式返回, 令牌也直接暴露在了浏览器地址栏, 实际上这种模式是OAuth 2.0 对公开(public)的客户端的授权流程进行了优化, 上面说到了客户端分为两种, 机密的的和公开的, 因为公开的客户端没有能力维护自己的机密凭证, 所以适合这种模式, 并且授权码模式需要客户端认证 (通过code换取access_token的时候,需要使用 Http Basic认证,或者传入client_secret) , 而隐式授权在整个流程中并没有客户端认证,所以是不安全也不推荐使用的。

请求参数:

response_type 这里固定是 token

GEThttps://www.authorization-server.com/oauth2/authorize?response_type=token&client_id=s6BhdRkqt3&scope=user&state=8b815ab1d177f5c8e &redirect_uri=https://www.client.com/callback

响应参数:

https://www.client.com/callback#access_token=2YotnFZFEjr1zCsicMWpAA&state=8b815ab1d177f5c8e&token_type=Bearer&expires_in=3600

这里注意 access_token 实际上并不是一个url 参数, 它前面是 # 号, 表示一个fragment, # 有别于 ?? 后面的查询字符串会被网络请求发送到服务器,而 fragment 则不会发送到服务器, 但是js是可以解析到fragment的值, 也就是 access_token, 这个设计很巧妙!

Resource Owner Password Credentials Grant 密码凭证模式

b55f1698d0d57e01ccae6db089fe2b70.png

密码模式就更简单粗暴了, 用户直接把账号密码告诉客户端, 客户端向授权服务器发起POST请求, 并携带用户名和密码, 授权服务器验证通过后, 返回访问令牌和可选的刷新令牌, 这种模式的特点是, 用户和客户端是高度信任的。

请求参数:

POST /token HTTP/1.1Host: www.authorization-server.comAuthorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JWContent-Type: application/x-www-form-urlencodedgrant_type=password&username=johndoe&password=A3ddj3w

响应参数:

HTTP/1.1 200 OKContent-Type: application/json;charset=UTF-8Cache-Control: no-storePragma: no-cache{  "access_token":"2YotnFZFEjr1zCsicMWpAA",  "token_type":"Bearer",  "expires_in":3600,  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" }

Client Credentials Grant 客户端凭证模式

4391f06c86c70134b1a13338209e09d6.png

客户端凭证模式的特点是, 客户端就是资源所有者, 客户端访问资源也不需要用户的授权, 因为这个过程中没有用户, 资源本身就属于客户端, 通过在请求体中传入 client_id,client_secret参数或者Http Basic 进行客户端认证, 这种模式很适合后端服务或者api之间调用的场景。

请求参数:

此处的 grant_type 固定是 client_credentials

POST /token HTTP/1.1Host: www.authorization-server.comAuthorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JWContent-Type: application/x-www-form-urlencodedgrant_type=client_credentials

响应参数:

HTTP/1.1 200 OKContent-Type: application/json;charset=UTF-8Cache-Control: no-storePragma: no-cache{  "access_token":"2YotnFZFEjr1zCsicMWpAA",  "token_type":"Bearer",  "expires_in":3600,  "example_parameter":"example_value"}

总结

本文介绍了 OAuth 2.0 核心协议, 主要参考 RFC 6749 (The OAuth 2.0 Authorization Framework) 核心协议 , 相信读完本文, 你会发现有些流程其实是不安全的, 没错, 其中的隐式授权和密码授权模式已经不再建议使用, 因为隐式授权从一开始就没有真正安全过, 这里介绍一下背景, 当时 OAuth 2.0 出现的时间点在2010年左右, 移动端应用是全新的,单页面应用程序(SPA) 也才刚开始出现, 当时的Web生态和现在还是差别很大, 由于技术问题, 并不能使用常规的 OAuth 模式进行授权。对于现在来说, 推荐使用专门为移动设备应用而设计的 PKCE (RFC 7636) 模式, 它是OAuth 2.0 核心的一个扩展协议, 也是最近几年移动设备应用授权的最佳实践。

目前 OAuth 2.1 也是一项正在进行中的工作, 它围绕 OAuth 2.0 对其授权功能进行加强和优化, 下篇文章我会继续介绍 OAuth 2.1 的新功能。

References

•https://www.rfc-editor.org/rfc/rfc6749•https://www.rfc-editor.org/rfc/rfc6750•https://www.rfc-editor.org/rfc/rfc7662•https://www.rfc-editor.org/rfc/rfc5849•https://www.rfc-editor.org/rfc/rfc2617•https://www.rfc-editor.org/rfc/rfc7519•https://oauth.net/2/•https://www.youtube.com/watch?v=CHzERullHe8•https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-13#section-3.4

😃 欢迎关注微信公众号【全球技术精选】


dc77d3e220e99b5555d90b5227c3854a.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL 分页查询语句大全即(查找第N到M条记录的方法)

SQL 分页查询语句大全即(查找第N到M条记录的方法) 第一种方法,我的原创方法 row2 表示分页行数 page1 表示页码 getnumrow*page select * from (select top row * from (select top getnum * from Newslist order by id desc) order by id …

揭开不一样的世界,这5部纪录片绝对不能错过!

纪录片一直都是增长见识又带给你力量的东西,你可能忙于学业、生活、工作而不能行万里路,但至少你还可以看纪录片,从一方屏幕看到整个世界。今天就为大家整理了5部高分纪录片,文末附领取方式,快收下吧~01与摩根弗里曼一…

算术几何平均matlab,算术-几何平均数——高斯的发现

“算术-几何平均数”既不是算术平均数,也不是几何平均数,由素有“数学王子”之称的德国数学家高斯首先发现和研究。算术-几何平均数,当然与“算术平均数”和“几何平均数”这两个概念有很深的关系。我们知道,但凡一个数学概念或定…

.NET Core TLS 协议指定被我钻了空子~~~

【导读】此前,测试小伙伴通过工具扫描,平台TLS SSL协议支持TLS v1.1,这不安全,TLS SSL协议至少是v1.2以上才行,想到我们早已将其协议仅支持v1.3,那应该非我们平台问题。近日,第三方合作伙伴再次…

Android之CheckBox复选框控件使用inelayout.xml Xml代码

linelayout.xml Xml代码<?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android" android:layout_width"match_parent" android:layout_height&quo…

frame buffer编程--画点功能和新增字符串代替RGBT

&#xff08;一&#xff09;&#xff1a;写在前面 这一次进行了一个比较大的迭代&#xff0c;在这里我先把相对于上一个版本的改进做一个解释&#xff1a; 1:进一步完善画点&#xff0c;增加了使用字符串代替RGBT值2:实现字符串解析出RGBT值3:增加了画圆的算法4:进一步增强了代…

这篇博士毕业论文致谢句句诛心......

全世界只有3.14 % 的人关注了爆炸吧知识本文来源&#xff1a;学术志综合自小木虫、网络等&#xff0c;作者yechm AUT博士毕业论文感谢信&#xff1a;我出生的时候是一个下雪的深夜&#xff0c;我的父亲在床边生了一堆柴火&#xff0c;我的母亲躺在四周漏风的那间破屋角落的床上…

30分钟通过Kong实现.NET网关

什么是KongOpenrestry是一个基于Nginx与Lua的高性能平台&#xff0c;内部有大量的Lua库。其中ngx_lua_moudule使开发人员能使用Lua脚本调用Nginx模块。Kong是一个Openrestry程序&#xff0c;而Openrestry运行在Nginx上&#xff0c;用Lua扩展了nginx。所以可以认为Kong Openres…

Proxy模式简介和用例

在软件系统中&#xff0c;有些对象有时候由于某些原因&#xff08;比如对象创建开销很大&#xff0c;或者某些操作需要安全控制&#xff0c;或者需要进程外的访问&#xff09;&#xff0c;如果直接访问会给使用者或者系统结构带来很多麻烦&#xff0c;这时可以在客户程序和目标…

这个小姐姐真的很火辣......

1 穿着十分火辣的美女...▼2 你还有理了&#xff1f;▼3 学生&#xff1a;我们要把老师照片挂墙上&#xff01;▼4 喜悦中带着阵阵悲伤...▼5 你瞅啥&#xff1f;瞅你咋地&#xff01;▼6 一时竟没发现哪里不对▼7 老板&#xff0c;我们KTV最漂亮的都在这了▼你点的每个赞…

RPC调用框架比较分析

什么是RPC&#xff1a; RPC&#xff08;Remote Procedure Call Protocol&#xff09;——远程过程调用协议&#xff0c;它是一种通过网络从远程计算机程序上请求服务&#xff0c;而不需要了解底层网络技术的协议。 简言之&#xff0c;RPC使得程序能够像访问本地系统资源一样&am…

VS扩展CodeMaid代码整理插件

CodeMaid是Visual Studio的开源扩展&#xff0c;用于清理和简化我们的C&#xff03;&#xff0c;C &#xff0c;F&#xff03;&#xff0c;VB&#xff0c;PHP&#xff0c;PowerShell&#xff0c;JSON&#xff0c;XAML&#xff0c;XML&#xff0c;ASP&#xff0c;HTML&#xff0…

Centos5 install vnc

2019独角兽企业重金招聘Python工程师标准>>> 很详细的install steps: http://wiki.centos.org/HowTos/VNC-Server#head-76401321dae4d80916a7fd7e710272a9b85c9485 ---------------------------------------------------------------------------------------------…

北大学霸隐居20年,王青松花光350万后,如今怎么样了?

全世界只有3.14 % 的人关注了爆炸吧知识传说我国&#xff0c;本科生遍地走&#xff0c;研究生多如狗。但一估算&#xff0c;从1977年高考恢复以来&#xff0c;国内现在的本科率竟然还不到5%。这样一想&#xff0c;30多年前的本科生数量肯定更少&#xff0c;也更珍贵。如果是北大…

文件给制实施规定的实例(GB8567-88)

尽管在文件编制中存在着很多灵活性&#xff0c;然而&#xff0c;文件的编制确实是非常必要的&#xff0c;其意义如前所述。为了控制这种灵活性&#xff0c;保证文件编制能达到应该达到的目的&#xff0c;对于具体的软件开发任务&#xff0c;应编制的文件的种类、详细程度应取决…

python 内存数据库下载,Python 文件存储和数据库

Python 中数据存储的方式和其他语言没什么区别&#xff0c;主要分为两个方面&#xff1a;文件存储和数据库存储。文件存储文件存储的方法也分为很多种&#xff0c;主要包括&#xff1a;Python 内置方法NumPy 模块方法os 模块方法csv 模块方法Python 内置方法在不需要借助任何外…

c#10中的namespace

A、namespace是c#用来管理类型隔离的关键字&#xff0c;在不同的namespace下可以相同名称的类型&#xff0c;并且namespace是可以嵌套的。Demo01.csnamespace NameSpaceDemo {internal class Demo01Class{ }namespace NSDemo01{internal class Demo01Class{}}namespace NSDemo…

岛国小姐姐来例假时,男朋友背着她偷偷查手机......

1 大猪蹄子们都好好学学▼2 人形扫地机&#xff1f;&#xff1f;&#xff1f;▼3 妈&#xff0c;看下你儿子大学四年积攒的宝藏▼4 你以为养老院很无聊&#xff1f;▼5 这个事是全世界统一的吗&#xff1f;▼6 爸爸&#xff1a;今天做个温柔的人吧▼7 那些隐藏在民间的车…

mysql-普通查询(General Query)慢查询(Slow Query)相关日志配置

2019独角兽企业重金招聘Python工程师标准>>> 配置 配置方法一: 服务启动时 # vi /etc/my.cnf ... log-outputTABLE,FILE general-log1 slow-query-log1# systemctl restart mysqldlog-output默认是FILE,还有个值是NONE,就不输出日志了.我这里演示的是表和日志文件都…

他让全世界凶手睡不着觉,现实版福尔摩斯,退休了4次又被拽回来工作,无敌实在是太寂寞了~...

全世界只有3.14 % 的人关注了爆炸吧知识今天要说一位最近在中国圈粉无数萌萌哒老爷爷他是《挑战不可能》里的李博士也是世界上最牛逼的刑侦鉴识专家DrHenryLee李昌钰人称现实版福尔摩斯他是全球身价最高的鉴识专家之一据说工作酬劳是10000美元/时如果哪个案子他都破不了那这个c…