什么是 OAuth2 协议?

  1. 互联网上的一款安全协议
  2. OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。
  3. OAuth主要有OAuth1.0aOAuth2.0两个版本,并且二者完全不同,且不兼容。OAuth2.0是目前是市面上最广泛使用的版本

如下图所示,第三方登录就是 Oauth2 的一种应用场景

访问授权协议 - OAuth2 - 图1

为什么要有 OAuth2?

随着时代的发展,对于企业而言,可能会遇到下面这些问题

  • 不同服务之间的分别部署,用户的登录问题,如果让用户在不同服务上注册账号密码,过于麻烦
  • 第三方程序接入提供信息的问题,如何确定授权范围(授权的范围)
  • 如果选择将用户账号密码暴露给第三方或不同服务,如何解决用户修改账号密码授权失效的问题
    ……

为了解决上面的问题,OAuth2 诞生了

OAuth2 的四种授权模式

授权码模式

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与” 服务提供商” 的认证服务器进行互动。分为下述步骤:

  1. A)用户访问客户端,后者将前者导向认证服务器。
  2. B)用户选择是否给予客户端授权。
  3. C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"redirection URI),同时附上一个授权码。
  4. D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
  5. E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

授权码模式是最繁琐的模式,也是安全系数最高的模式,因此市面上最常见的就是该模式 `

简化模式(隐式授权)

简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了 “授权码” 这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。分为下述步骤:

  1. A)客户端将用户导向认证服务器。
  2. B)用户决定是否给于客户端授权。
  3. C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URIHash部分包含了访问令牌。
  4. D)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。
  5. E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
  6. F)浏览器执行上一步获得的脚本,提取出令牌。
  7. G)浏览器将令牌发给客户端。

简化模式一般用于没有后端应用的时候,常见于第三方单页面应用。例如调查问卷等

密码模式(资源所有者密码凭证

密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向 “服务商提供商” 索要授权。分为下述步骤:

  1. A)用户向客户端提供用户名和密码。
  2. B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
  3. C)认证服务器确认无误后,向客户端提供访问令牌。

客户端模式(客户端凭证)

客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向 “服务提供商” 进行认证。严格地说,客户端模式并不属于 OAuth 框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求 “服务提供商” 提供服务,其实不存在授权问题。分为下述步骤:

  1. A)客户端向认证服务器进行身份认证,并要求一个访问令牌。
  2. B)认证服务器确认无误后,向客户端提供访问令牌。

授权模式类比

授权模式 优点 缺点 应用场景
授权码模式 安全性较高 功能最完整 流程最严密 需要额外的交互步骤 客户端需要存储和管理授权码 适用于有自己的服务器的应用 例如公网的开放平台
简化模式 流程简单 安全性较低 访问令牌容易泄露且不可刷新 适用于无后端服务的纯前端应用 例如纯静态页面应用
密码模式 简单易用 无额外的交互步骤 安全性较低 用户的账号和密码直接暴露给客户端 资源所有者与客户端具有良好信任关系的场景 例如客户端是设备的操作系统或具备高权限的应用
客户端模式 简单易用 安全性较低 不涉及用户的身份验证 适用于客户端需要访问自己拥有的资源的场景 例如移动应用访问自己的后台服务器 ,或者在微服务架构中服务之间的调用

OAuth2 实际应用:如何实现微信第三方登录

授权码模式

1. 注册应用

https://open.weixin.qq.com/ 网站注册应用,以获取 app_id 以及 app_secret

2. 前端接收 code

流程

1)用户点击页面上的第三方登录,拼接好对应的路由,并在浏览器中打开

拼接的路由结构如下

https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

参数说明

参数 是否必须 说明
appid 应用唯一标识(前面认证网页应用中获得)
redirect_uri 重定向地址,需要进行 UrlEncode(前面认证网页应用中获得)
response_type 填 code
scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写 snsapi_login 即可
state 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止 csrf 攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加 session 进行校验
  1. 用户进行扫描,微信会进行验证,并返回到回调的 url 上,所以前端要监听对应的回调地址,判断微信是否返回

  2. 接受微信返回的 code,并发送给后端

3. 后端接受凭证并通过 code 获取 access_token

流程

1)后端拼接路由并发送请求

路由结构如下

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

参数说明

参数 是否必须 说明
appid 应用唯一标识,在微信开放平台提交应用审核通过后获得
secret 应用密钥 AppSecret,在微信开放平台提交应用审核通过后获得
code 填写第一步获取的 code 参数
grant_type 填 authorization_code

2)接收微信返回的信息

ex:

  1. {
  2. "access_token":"ACCESS_TOKEN",
  3. "expires_in":7200,
  4. "refresh_token":"REFRESH_TOKEN",
  5. "openid":"OPENID",
  6. "scope":"SCOPE",
  7. "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
  8. }

参数说明

参数 说明
access_token 接口调用凭证
expires_in access_token 接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新 access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔
unionid 当且仅当该网站应用已获得该用户的 userinfo 授权时,才会出现该字段。

4. 通过 access_token 获取用户信息

流程

1)拼接路由并发送请求

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

参数说明

参数 是否必须 说明
access_token 调用凭证(上一个请求中获得)
openid 普通用户的标识,对当前开发者帐号唯一(上一个请求中获得)
lang 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语,默认为 zh-CN

2)接收返回信息

  1. {
  2. "openid":"OPENID",
  3. "nickname":"NICKNAME",
  4. "sex":1,
  5. "province":"PROVINCE",
  6. "city":"CITY",
  7. "country":"COUNTRY",
  8. "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
  9. "privilege":[
  10. "PRIVILEGE1",
  11. "PRIVILEGE2"
  12. ],
  13. "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
  14. }

参数说明

参数 说明
openid 普通用户的标识,对当前开发者帐号唯一
nickname 普通用户昵称
sex 普通用户性别,1 为男性,2 为女性
province 普通用户个人资料填写的省份
city 普通用户个人资料填写的城市
country 国家,如中国为 CN
headimgurl 用户头像,最后一个数值代表正方形头像大小(有 0、46、64、96、132 数值可选,0 代表 640*640 正方形头像),用户没有头像时该项为空
privilege 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
unionid 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的 unionid 是唯一的。