信息的密度和质量对于知识学习过程尤为重要,构建一个完整的知识树也有利于全面掌握知识。所以下方会贴很多链接内容,以及按照知识树和提问的方式来学习Oauth 2.0 。链接都是我通过精心阅读和提炼后的内容,希望点击阅读。
OAuth 2.0 is a protocol that allows distinct parties to share information and
resources in a secure and reliable manner.
OAuth 2.0是一种协议,它允许不同的模块以安全可靠的方式和共享信息和资源。
1 Oauth2.0 协议介绍解决什么问题?
1.例一
有一个"云冲印"的网站,可以将用户储存在Google的照片,冲印出来。用户为了使用该服务,必须让"云冲印"读取自己储存在Google上的照片。问题是只有得到用户的授权,Google才会同意"云冲印"读取这些照片。那么,"云冲印"怎样获得用户的授权呢?
传统方法是,用户将自己的Google用户名和密码,告诉"云冲印",后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。
- "云冲印"为了后续的服务,会保存用户的密码,这样很不安全。
- Google不得不部署密码登录,而我们知道,单纯的密码登录并不安全。
- "云冲印"拥有了获取用户储存在Google所有资料的权力,用户没法限制"云冲印"获得授权的范围和有效期。
- 用户只有修改密码,才能收回赋予"云冲印"的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。
- 只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。
2.例二
新浪微博就是你的家。偶尔你会想让一些人(第三方应用)去你的家里帮你做一些事,或取点东西。你可以复制一把钥匙(用户名和密码)给他们,但这里有三个问题:
- 别人拿了钥匙后可以去所有的房间
- 别人拿到你的钥匙后也许会不小心丢到,甚至故意送到它人手里。这样你都不知到谁有你家钥匙。
- 过一段时间你也许会想要回自己的钥匙,但别人不还怎么办?
OAuth就是为了解决上面这些问题而诞生的。OAuth 是高级钥匙:
- 你可以配置不同权限的钥匙。有些只能进大厅(读取你的微博流)。有些钥匙可以进储藏柜(读取你的相片)
- 钥匙上带着指纹验证的(指纹 = appkey)。 收到钥匙的人只能自己用,不能转让
- 你可以远程废除之前发出的钥匙
详细内容看:
知乎 OAuth 授权的工作原理是怎样的?足够安全吗?
阮一峰 理解OAuth 2.0
2 Oauth的商业化意义
- 支持第三方登录也对这些网站,免去了复杂的注册过程,用户体验更佳,更愿意去登录。这样在提高留存率的同时,也更加易于收集用户的一些非敏感信息等
- 可以借助一些社交类的第三方账号进行站点推广等。
- Oauth的安全性为公司业务平稳带来保障
3 进入Oauth 2.0之前了解两个概念
authentication(认证) 和authorization(授权)
Authentication is the process of validating whether a person (or system) is actually who they say they are. An example of this is when you go to the bank to withdraw money, and you provide your bank card and PIN to the teller. In some cases, the teller may ask for additional identification, such as your driver's license, to verify your identity. You may recognize this in other instances when you provide your username and password to a website, say, to view a document.
Authorization is the process of determining what actions you are allowed to perform once you have been authenticated. Referring to our previous bank example, once the teller has verified who you are, they can then proceed to fulfill your request to withdraw money. In order to do this, they must check whether you are allowed to withdraw money from the account that you are requesting (that is, you are actually the owner of the account). Relating to our website example, once you have authenticated by providing your username and password, the website will then check to see whether you are indeed allowed to see the document that you are requesting. This is usually done by looking up your permissions in some access control list.
Authorization typically involves two separate aspects that combine to describe the accessibility of the secured system.
The irst is the mapping of an authenticated principal to one or more authorities (often called roles). For example, a casual user of your website might be viewed as having visitor authority, while a site administrator might be assigned administrative authority.
The second is the assignment of authority checks to secured resources of the system. This is typically done at the time a system is developed, either through an explicit declaration in code or through coniguration parameters. For example, the screen that allows viewing of other users' events should be made available only to those users having administrative authority.
所以OAuth 2.0是一个授权框架,而不是认证框架。
The OAuth 2.0 Authorization Framework
Strictly speaking, the OAuth 2.0 protocol is actually an authorization protocol and not an authentication protocol. Because of this, OAuth 2.0 alone cannot provide federated identity. However, when used in a certain way, and in conjunction with other protocols, OAuth 2.0 can provide federated authentication, which is a key component to federated identity systems.
这些内容来自Mastering OAuth 2.0图书
本书比较简洁的整理了Oauth2.0的每个流程的细节,可以看一下。
4 所以说,Oauth 2.0 解决两个问题?
- Allowing a user to log into an application with another account. For example, Pinterest allowing users to log in with their Twitter accounts. This is known as federated identity.
- Allowing one service to access resources on another service on behalf of the user. For example, Adobe accessing your Facebook photos on your behalf. This is known as delegated authority.
5 Oauth 2.0的运行流程是啥?
OAuth 2.0 是目前比较流行的做法,它率先被Google, Yahoo, Microsoft, Facebook等使用。之所以标注为 2.0,是因为最初有一个1.0协议,但这个1.0协议被弄得太复杂,易用性差,所以没有得到普及。2.0是一个新的设计,协议简单清晰,但它并不兼容1.0,可以说与1.0没什么关系。所以,我就只介绍2.0。
在了解Oauth2.0的运行流程之前,先要了解的一些角色:
5.1 OAuth2.0定义的几种角色
图片来自architecture of spring security oauth,个人认为和官方释义一同构成了网络环境上最好的Oauth2.0 学习链接。
资源所有者(Resource Owner)
受保护资源所属的实体,比如资源的持有人等,下文的用户即资源所有者。
资源服务器(Resource Server)
托管资源的服务器,能够接收和响应持有令牌的资源访问请求,可以与授权服务器是同一台服务器,也可以分开。
授权服务器(Authorization Server)
授权服务器的主要职责是验证资源所有者的身份,并依据资源所有者的许可对第三方应用下发令牌。
客户端(Client)
客户端是OAuth服务的接入方,其目的是请求用户存储在资源服务器上的受保护资源,客户端可以移动应用、网页应用,以及电视应用等等。
5.2 流程
图片来自RFC 6749 ,可以说是Oauth2.0的官方释义The OAuth 2.0 Authorization Framework
(A) The client requests authorization from the resource owner. The authorization request can be made directly to the resource owner
(as shown), or preferably indirectly via the authorization
server as an intermediary.
(B) The client receives an authorization grant, which is a
credential representing the resource owner's authorization,
expressed using one of four grant types defined in this
specification or using an extension grant type. The
authorization grant type depends on the method used by the
client to request authorization and the types supported by the
authorization server.
(C) The client requests an access token by authenticating with the
authorization server and presenting the authorization grant.
(D) The authorization server authenticates the client and validates
the authorization grant, and if valid, issues an access token.
(E) The client requests the protected resource from the resource
server and authenticates by presenting the access token.
(F) The resource server validates the access token, and if valid, serves the request.
简短翻译一下:
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
不难看出来,上面六个步骤之中,B是关键,即用户怎样才能给于客户端授权? 有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。 下面看看四种授权模式。
6 客户端的授权模式有哪些?
来自官方释义The OAuth 2.0 Authorization Framework
OAuth 2.0定义了四种授权方式。
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
下面分别讲解:
6.1 授权码模式(authorization code)
(A) The client initiates the flow by directing the resource owner's user-agent to the authorization endpoint. The client includes
its client identifier, requested scope, local state, and a
redirection URI to which the authorization server will send the
user-agent back once access is granted (or denied).
(B) The authorization server authenticates the resource owner (via
the user-agent) and establishes whether the resource owner
grants or denies the client's access request.
(C) Assuming the resource owner grants access, the authorization
server redirects the user-agent back to the client using the
redirection URI provided earlier (in the request or during
client registration). The redirection URI includes an
authorization code and any local state provided by the client
earlier.
(D) The client requests an access token from the authorization
server's token endpoint by including the authorization code
received in the previous step. When making the request, the
client authenticates with the authorization server. The client
includes the redirection URI used to obtain the authorization
code for verification.
(E) The authorization server authenticates the client, validates the
authorization code, and ensures that the redirection URI
received matches the URI used to redirect the client in
step (C). If valid, the authorization server responds back with
an access token and, optionally, a refresh token.
(A)用户访问客户端,后者将前者导向认证服务器。
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。
(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
下面是上面这些步骤所需要的参数。
A步骤中,客户端申请认证的URI,包含以下参数:
- response_type:表示授权类型,必选项,此处的值固定为"code"
- client_id:表示客户端的ID,必选项
- redirect_uri:表示重定向URI,可选项
- scope:表示申请的权限范围,可选项
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
下面是一个例子。
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: server.example.com
C步骤中,服务器回应客户端的URI,包含以下参数:
- code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
下面是一个例子。
HTTP/1.1 302 Found Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA &state=xyz
D步骤中,客户端向认证服务器申请令牌的HTTP请求,包含以下参数:
- grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
- code:表示上一步获得的授权码,必选项。
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
- client_id:表示客户端ID,必选项。
下面是一个例子。
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
E步骤中,认证服务器发送的HTTP回复,包含以下参数:
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
下面是一个例子。
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
从上面代码可以看到,相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不得缓存。
6.2 简化模式(implicit)
(A) The client initiates the flow by directing the resource owner's user-agent to the authorization endpoint. The client includes its client identifier, requested scope, local state, and a
redirection URI to which the authorization server will send the
user-agent back once access is granted (or denied).
(B) The authorization server authenticates the resource owner (via
the user-agent) and establishes whether the resource owner
grants or denies the client's access request.
(C) Assuming the resource owner grants access, the authorization
server redirects the user-agent back to the client using the
redirection URI provided earlier. The redirection URI includes
the access token in the URI fragment.
(D) The user-agent follows the redirection instructions by making a
request to the web-hosted client resource (which does not
include the fragment per [[RFC2616](https://tools.ietf.org/html/rfc2616 ""Hypertext Transfer Protocol -- HTTP/1.1"")]). The user-agent retains the
fragment information locally.
(E) The web-hosted client resource returns a web page (typically an
HTML document with an embedded script) capable of accessing the
full redirection URI including the fragment retained by the
user-agent, and extracting the access token (and other
parameters) contained in the fragment.
(F) The user-agent executes the script provided by the web-hosted
client resource locally, which extracts the access token.
(G) The user-agent passes the access token to the client.</pre>
(A)客户端将用户导向认证服务器。
(B)用户决定是否给于客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌。
(D)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。
(E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
(F)浏览器执行上一步获得的脚本,提取出令牌。
(G)浏览器将令牌发给客户端。
下面是上面这些步骤所需要的参数。
A步骤中,客户端发出的HTTP请求,包含以下参数:
- response_type:表示授权类型,此处的值固定为"token",必选项。
- client_id:表示客户端的ID,必选项。
- redirect_uri:表示重定向的URI,可选项。
- scope:表示权限范围,可选项。
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
下面是一个例子。
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: server.example.com
C步骤中,认证服务器回应客户端的URI,包含以下参数:
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
下面是一个例子。
HTTP/1.1 302 Found Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA &state=xyz&token_type=example&expires_in=3600
在上面的例子中,认证服务器用HTTP头信息的Location栏,指定浏览器重定向的网址。注意,在这个网址的Hash部分包含了令牌。
根据上面的D步骤,下一步浏览器会访问Location指定的网址,但是Hash部分不会发送。接下来的E步骤,服务提供商的资源服务器发送过来的代码,会提取出Hash中的令牌。
6.3 密码模式(resource owner password credentials)
(A) The resource owner provides the client with its username and password.
(B) The client requests an access token from the authorization
server's token endpoint by including the credentials received from the resource owner. When making the request, the client authenticates with the authorization server.
(C) The authorization server authenticates the client and validates the resource owner credentials, and if valid, issues an access token.
(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
(C)认证服务器确认无误后,向客户端提供访问令牌。
密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
B步骤中,客户端发出的HTTP请求,包含以下参数:
grant_type:表示授权类型,此处的值固定为"password",必选项。
username:表示用户名,必选项。
password:表示用户的密码,必选项。
scope:表示权限范围,可选项。
下面是一个例子。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
C步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
6.4 客户端模式(client credentials)
(A) The client authenticates with the authorization server and
requests an access token from the token endpoint.
(B) The authorization server authenticates the client, and if valid,
issues an access token.
(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。
(B)认证服务器确认无误后,向客户端提供访问令牌。
A步骤中,客户端发出的HTTP请求,包含以下参数:
granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。
scope:表示权限范围,可选项。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
认证服务器必须以某种方式,验证客户端身份。
B步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
7 如何更新令牌token?
如果用户访问的时候,客户端的"访问令牌"已经过期,则需要使用"更新令牌"申请一个新的访问令牌。
客户端发出更新令牌的HTTP请求,包含以下参数:
granttype:表示使用的授权模式,此处的值固定为"refreshtoken",必选项。
refresh_token:表示早前收到的更新令牌,必选项。
scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。
下面是一个例子。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
8 Oauth2.0为何引入authorization_code?
来自文章帮你深入理解OAuth2.0协议
协议设计中,为什么要使用authorization_code来交换access_token?这是读者容易想到的一个问题。也就是说,在协议的第3步,为什么不直接将access_token通过重定向方式返回给Client呢?比如:
HTTP/1.1 302
Location:
https://www.facebook.com/?access_token=ya29.AHES6ZSXVKYTW2VAGZtnMjD&token_type=Bearer&expires_in=3600
如果直接返回access_token,协议将变得更加简洁,而且少一次Client与AS之间的交互,性能也更优。那为何不这么设计呢?协议文档[1]中并没有给出这样设计的理由,但也不难分析:
(1) 浏览器的redirect_uri是一个不安全信道,此方式不适合于传递敏感数据(如access_token)。因为uri可能通过HTTP referrer被传递给其它恶意站点,也可能存在于浏览器cacher或log文件中,这就给攻击者盗取access_token带来了很多机会。另外,此协议也不应该假设RO用户代理的行为是可信赖的,因为RO的浏览器可能早已被攻击者植入了跨站脚本用来监听access_token。因此,access_token通过RO的用户代理传递给Client,会显著扩大access_token被泄露的风险。 但authorization_code可以通过redirect_uri方式来传递,是因为authorization_code并不像access_token一样敏感。即使authorization_code被泄露,攻击者也无法直接拿到access_token,因为拿authorization_code去交换access_token是需要验证Client的真实身份。也就是说,除了Client之外,其他人拿authorization_code是没有用的。 此外,access_token应该只颁发给Client使用,其他任何主体(包括RO)都不应该获取access_token。协议的设计应能保证Client是唯一有能力获取access_token的主体。引入authorization_code之后,便可以保证Client是access_token的唯一持有人。当然,Client也是唯一的有义务需要保护access_token不被泄露。
(2) 引入authorization_code还会带来如下的好处。由于协议需要验证Client的身份,如果不引入authorization_code,这个Client的身份认证只能通过第1步的redirect_uri来传递。同样由于redirect_uri是一个不安全信道,这就额外要求Client必须使用数字签名技术来进行身份认证,而不能用简单的密码或口令认证方式。引入authorization_code之后,AS可以直接对Client进行身份认证(见步骤4和5),而且可以支持任意的Client认证方式(比如,简单地直接将Client端密钥发送给AS)。
9 spring security 中Oauth的分析
下面介绍在Spring Security OAuth在微服务中的使用
9.1 为什么需要做一个单独的认证授权服务?
为了保证服务对外的安全性,往往都会在服务接口采用权限校验机制,为了防止客户端在发起请求中途被篡改数据等安全方面的考虑,还会有一些签名校验的机制。
在分布式微服务架构的系统中,我们把原本复杂的系统业务拆分成了若干个独立的微服务应用,我们不得不在每个微服务中都实现这样一套校验逻辑,这样就会有很多的代码和功能冗余,随着服务的扩大和业务需求的复杂度不断变化,修改校验逻辑变得相当麻烦,一处改,处处改。所以我们需要把认证授权服务单独出来,做成一个服务进行调用。
9.2 授权服务的使用场景有哪些?
授权服务并不是每个应用的接口直接去调用,判断哪些用户有权限访问接口。 而是通过API网关进行统一调用。用户所有的请求都必须先通过API网关,API网关在进行路由转发之前对该请求进行前置校验,我们可以方便的使用OAuth2认证授权服务来做单点登录等操作。 可以使用OAuth2来实现对多个服务的统一认证授权。
9.3 Spring Security OAuth 是啥?
Spring Security OAuth is a library that provides functions necessary while building 3 roles such as Authorization Server, Resource Server, and Client as Spring applications among the roles defined in OAuth 2.0. Spring Security OAuth is the technique that works by linking with the functions provided by Spring Framework (Spring MVC) and Spring Security, and it can build the authorization server, resource server and client by appropriate configuration (Bean definition) of default package provided by Spring Security OAuth. Further, many extension points are provided similar to Spring Framework and Spring Security in order to incorporate the requirements that cannot be implemented in default package provided by Spring Security OAuth.
Spring Security OAuth 是OAuth 2.0和Spring 框架的结合。
10 spring security Oauth的使用
todo
11 参考文章链接
https://github.com/wiselyman/uaa-zuul
网友评论