什么是OAuth2
是开放授权的一个标准,旨在让用户允许第三方应用去访问改用户在某服务器中的特定私有资源,而可以不提供其在某服务器的账号密码给到第三方应用
通俗的话可以这样去理解,假如你们公司正在开发一个 第三方应用XXX,该应用会需要在微信中分享出来一个活动页,该活动需要让微信用户去参与,你们的应用需要收集到用户的姓名,头像,地域等信息,那么问题来了?你的应用如何才能拿到所有参与活动的微信用户的基本信息呢?
根据以上示例,可以将OAuth2分为四个角色:
Resource Owner:资源所有者 即上述中的微信用户
Resource Server:资源服务器 即上述中的微信服务器,提供微信用户基本信息给到第三方应用
Client:第三方应用客户端 即上述中你公司正在开发的第三方应用
Authorication Server:授权服务器 该角色可以理解为管理其余三者关系的中间层
不难看出,OAuht2 解决问题的关键在于使用授权服务器
提供一个访问凭据
给到第三方应用
,让第三方应用
可以在不知道资源所有者
在资源服务器上的账号和密码
的情况下,能获取到资源所有者
在资源服务器
上的受保护资源
,这里的受保护资源就是微信用户的姓名以及头像等信息
。
OAuth2 授权流程
引用 blackheart 博主的流程图
拿上述的获取微信用户信息示例来说
微信用户a,访问第三方应用分享到微信中的活动页面,第三方应用即向微信授权服务器 发起授权请求以获取该微信用户a在微信服务器上的姓名,头像等基本信息(私有资源)
微信授权服务器
接收到第三方应用的授权请求
(包含第三方应用的回调地址的),并引导
用户确认授权
(也可以选择用户静默授权
)后,返回授权许可(code)给到第三方应用(根据授权请求传入的回调地址
)第三方应用
拿到
授权许可code
后,再次向微信授权服务器发起访问令牌
的请求(携带身份app_id
等)微信
授权服务器
验证第三方应用的身份
以及授权许可code
,验证通过后将下发访问令牌access_code,此外还有刷新令牌
以及令牌过期时间
等信息给到第三方应用第三方应用
拿到访问令牌
后向微信资源服务器发起请求资源
,即请求微信用户a的姓名,头像,地域
等基本信息微信资源服务器根据访问令牌,返回微信用户a的基本信息给到第三方应用。
至此,整套授权流程结束,可以看出访问令牌
是整个流程中的核心
访问令牌:可以理解为对第三方应用可以在微信资源服务器中得到微信用户a的哪些信息的一个抽象集合,微信资源服务器拿到访问令牌后就知道是哪个第三方应用需要获取哪个微信用户的什么受限资源
如何部署OAuth2
部署OAuth2之前,需要理解上述四种角色之间的关系,以及每一种角色需要提供那些功能,以及将各种安全性考虑进去等等
角色 | 功能 | 备注 |
---|---|---|
认证服务器 | 提供授权实现 | 提供类似获取授权许可(code),访问令牌(access_token)等接口 |
资源服务器 | 提供第三方应用程序注册接口以及开放相应受保护资源的API | 第三方应用注册,是为了保证第三方应用的来源安全性 |
第三方应用 | 申请注册成为资源服务器的第三方应用以及消费资源服务器提供的受限资源API | 类似微信公众号申请操作,由授权服务器提供标识第三方应用的 app_id & app_secret |
用户 | 不需要做什么额外的改动,只需要点击确认授权即可 |
一般情况下授权服务器的工作由资源服务器提供,主要提供两类接口
- 授权接口:接受第三方应用的授权请求,引导用户到资源服务器完成登陆授权的过程
- 获取访问令牌接口:使用授权接口提供的许可凭证来颁发用户的访问令牌给到第三方应用,或者又第三方应用更新过期的访问令牌。
除此之外,还需要提供一个让第三方应用程序注册的管理后台,当第三方应用注册后会给到第三方应用一个app_id & app_secret ,app_secret是第三方应用程序的私钥,不允许在授权过程中传递的,主要用户安全加密用。
OAuth2中的有哪些授权许可
前面的示例中,第三方应用需要首先请求授权服务器以获取到授权许可code,再通过授权许可code去请求访问令牌,OAuth2中定义了四种许可类型以扩展OAuth2的机制
- 授权码 Authorization Code
- 隐式许可 Implicit
- 资源所有者密码凭证 Resource Owner Password Credentials
- 客户端凭证 Client Credentials
Authorization Code
授权码是OAuth2中最常用的一种授权许可类型,要求第三方应用需要有可公开访问的服务器来接收授权许可code,即上述中所说的回调地址。
引用 blackheart 博主的流程图
简要阐述一下各步骤
- 授权码请求
第三方应用使用用户代理(浏览器,或自己的服务器)访问微信授权服务器提供的一个url,该url就是提供获取授权码的url,第三方应用需要传递一下参数
response_type:(必传)此时为"code"
app_id:(必传)微信服务器下发的标识第三方应用的
redirect_uri:(必传)授权成功后的重定向地址
scope:(可选)标识授权范围
state:(推荐)第三方应用提供的一个字符串,微信授权服务器会原样返回
示例请求
GET /authorize?response_type=code&app_id=wx201800a28199&state=wilson&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Foauth2&scope=user,photo HTTP/1.1
- 授权码返回
微信授权服务器验证第三方应用再上一步中传递的参数,确认无误后会提供一个页面给微信用户a登录或者手动确认授权操作,操作超过后微信授权服务器会根据redirect_uri重定向到该地址,并携带下发的授权许可code
类似重定向地址
HTTP/1.1 302 Found
Location: https://client.example.com/oauth2?code=SplxlOBeZQQYbYS6WxSbIA&state=wilson
- 访问令牌请求
第三方应用根据上一步拿到的授权码code以及app_id,重定向地址等参数,再次请求微信授权服务器,请求获取访问令牌access_token
grant_type:(必传)值为"authorization_code"
code:(必传)值为上一步获取到的授权码code
redirect_uri:(必传)必须和第一步获取授权码中的一致
app_id:(必传)标识第三方应用id
请求示例如下
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&app_id=wx201800a28199&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Foauth2
- 访问令牌返回
微信授权服务器返回访问令牌和一些刷新令牌,令牌过期时间等信息给到第三方应用
返回示例如下:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
- 受限资源获取
第三方应用根据访问令牌去微信资源服务器获取微信用户a的基本信息。
Implicit
此种授权方式是授权码方式的简化版本,其中省略了颁发授权码code给第三方应用的步骤,通过一次请求微信授权服务器直接返回访问令牌以及刷新令牌等信息,适用于没有server服务器来接受处理授权码的第三方应用
- 授权请求
请求参数示例
response_type:(必填)此处值为 "token"
app_id:(必传)微信服务器下发的标识第三方应用的
redirect_uri:(必传)授权成功后的重定向地址
scope:(可选)标识授权范围
state:(推荐)第三方应用提供的一个字符串,微信授权服务器会原样返回
请求url示例
GET /authorize?response_type=token&app_id=wx201800a28199&state=wilson&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Foauth2&scope=user,photo HTTP/1.1
- 授权返回
返回参数示例
access_token: 访问令牌
refresh_token:刷新令牌
expire_in:过期时间
返回url示例
HTTP/1.1 302 Found
Location:
http://client.example.com/oauth2#access_token=2YotnFZFEjr1zCsicMWpAA&state=wilson&expires_in=3600
Resource Owner Password Credentials Grant
该授权模式是第三方应用直接使用微信用户a的账号+密码来直接请求微信授权服务器access_token,该模式适用于微信资源服务器高度信任第三方client的情况
- 访问令牌请求
请求参数示例
grant_type:(必填)值固定为 "password"
user_name:(必填)微信用户登录名
password:(必填)用户登录密码
scope:可选 标识授权范围
请求url 示例
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=blackheart&password=1234
- 访问令牌返回
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
Client Credentials Grant
此类型更加简化,第三方应用直接使用自己的名义而不是微信用户a的名义去要求访问微信资源服务器的一些受保护资源,针对第三方应用获取微信资源服务器下的所有微信用户的信息而不是单个微信用户a的信息
- 授权请求(以自己的名义)
请求参数示例
grant_type:(必填)值固定为 "client_credentials"
scope:可选 标识授权范围
- 授权返回
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
OAuth2 刷新令牌
在上述第三方应用获取到访问令牌后,一般会同时得到一个过期时间以及刷新令牌,以在访问令牌失效时可以由第三方应用自动获取新的访问令牌,而不是由微信用户a再次授权一遍。
当访问令牌过期时,由第三方应用调用微信授权服务器的刷新令牌接口,传递以下参数即可。
grant_type:必填 值为 "refresh_token"
refresh_token:必填 值为第三方应用得到访问令牌同时拿到的刷新令牌
- 刷新令牌请求
POST /token HTTP/1.1
Host: server.example.com
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
- 刷新令牌返回
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
这样就可以一直使用有效的访问令牌啦
OAuth2 安全问题
互联网安全应引起足够的重视,防止出现重大事故
- 要求Authorization server进行有效的第三方应用身份验证
- app_serect,access_token,refresh_token,code等敏感信息的安全存储(不得泄露给第三方)、传输通道的安全性(TSL的要求)
- 维持refresh_token和第三方应用的绑定,刷新失效机制
- 维持Authorization Code和第三方应用的绑定,这也是state参数为什么是推荐的一点,以防止CSRF
- 保证上述各种令牌信息的不可猜测行,以防止被猜测得到