内容简介:作者 | 小牛Java 工程师,关注服务端技术
作者 | 小牛
Java 工程师,关注服务端技术
在我们的日常生活中,登录一个网站或 APP 时经常会选择微信、 QQ 或其他账号登录。这种情况我们就称为第三方登录。那么第三方登录的实现机制是什么呢?
基础概念
首先需要了解两个概念:OpenID 和 OAuth
OpenID:
OpenID是一个去中心化的网上身份认证系统。他是网站或应用中唯一对应用户身份的标识,网站或应用可将此ID进行存储,便于用户下次登录时辨识其身份,或将其与用户在网站上或应用中的原有账号进行绑定。
常见的对于微信来说:OpenID 是微信用户在开发者应用 AppId 下的唯一用户标识(AppId不同,则获取到的 OpenID 就不同),可用于永久标记一个用户。
OAuth:
OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容。
OAuth2.0 标准协议相对于之前的 OAuth1.0 协议,其认证流程更简单和安全。现在大多数应用都会使用 OAuth2.0 来进行用户身份验证和获取用户授权,
OAuth2.0
下面的主要篇幅会介绍 OAuth2.0 协议。
rule (角色)
如图所示,在 OAuth 2.0 中定义有以下角色:
-
Resource Owner (资源所有者)
-
Resource Server (资源服务器)
-
Client Application (客户端应用)
-
Authorization Server (认证服务器)
举例来说:小明使用微信登录知乎APP,那么小明是 Resource Owner,Resource Server 和 Authorization Server 都是微信服务,逼乎APP是Client Application。需要注意的是 Resource Server 和 Authorization Server 可以是同一个服务,也可以分开独立部署。
常用 Grant Types (认证授权模式)
OAuth2.0 常认证授权使用的模式如下:
Authorization Code
上图详细展示了 Authorization Code 模式的流程,或许我们直接参考 腾讯开放平台的流程去理解上图会更轻松一些:
-
Step1:放置QQ登录按钮
-
Step2:获取Authorization Code
-
Step3:通过Authorization Code获取Access Token
-
Step4:使用Access Token来获取用户的OpenID
-
Step5:使用Access Token以及OpenID来访问和修改用户数据
适用场景举例:大多数使用后台验证并授权的应用,例如:小明使用 QQ 登录一个网站。
模拟请求(以微信登录为例):
获取 Authorization Code
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:获取 code 后跳转的Url,
-
scope:授权作用域
用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数
redirect_uri?code=CODE&state=STATE
通过 Authorization Code 获取 Access Token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
-
secret:应用密钥 AppSecret
-
code:授权码 Authorization Code
Implicit
我们同样参考 腾讯开放平台 的流程去理解上图。
-
Step1:放置QQ登录按钮
-
Step2:获取Access Token
-
Step3:使用Access Token来获取用户的OpenID
-
Step4:使用Access Token以及OpenID来访问和修改用户数据
可以看出其与 Authorization Code 区别仅在于当用户成功登录之后,重定向到客户端应用时,access token会直接返回给客户端应用,也就是说 access token 在客户端应用中是可见的。
适用场景举例:单页 Web 应用。小明在一个营销 H5 页面给群里的小伙伴投票。
模拟请求 (QQ 登录为例):
获取 Access Token
https://graph.qq.com/oauth2.0/authorize?response_type=token&client_id=[YOUR_APPID]&redirect_uri=[YOUR_REDIRECT_URI]&scope=[THE_SCOPE]
如果用户允许授权,将会重定向到redirect_uri的网址上,并且带上 Access Token 参数
http://www.qq.com/?#access_token=YOUR_ACCESS_TOKEN&expires_in=3600
Password
在应用中直接使用用户名和密码登录。
适用场景举例:可信赖的、自有的应用。例:小明使用 QQ 账号密码登录 WeGame 玩 LOL。
Client Credentials
用于访问跟用户无关的资源。
适用场景举例:获取微信公众平台的 access_token。
模拟请求:
公众号获取 access_token
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
返回数据如下:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
小结
大体上以上几种认证模式的使用场景如下图:
下面是部分需要补充的概念:
-
client type:
-
Web App:web/wap 应用。
-
User Agent based app:用户与认证服务器交互所使用的浏览器或移动应用,可以认为是一个登录器。
-
Native App: 原生应用, 包括移动 App 和桌面应用。
-
其他:
-
first party:足够信任的客户端,可以处理最终用户的授权凭据。例如上文说到的 WeGame 客户端
扩展 Grant Types
除了上面最常见的模式之外,还用一些特殊模式也会使用得到。
Refresh Token
OAuth 2.0 默认的 access_token 有效时间为两小时。使用 Refresh Token 刷新已经过期的 access_token,避免应用与用户进一步交互。
一般 Refresh Token 模式会与 Authorization Code 模式结合使用,由于 access_token 拥有较短的有效期,当 access_token 超时后,可以使用 Refresh Token 进行刷新。
模拟请求:
刷新 access_token 有效期
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
请求响应如下:
{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
Device Code
部分硬件不能很方便的进行输入操作,这时就可以利用 Device Code 模式进行认证授权。
一般有以下的方案
-
每个设备都拥有一个唯一的设备码,通过外部已登录的用户,点击授权Url 填入对应的code,确认设备和用户的绑定关系,并授权。
-
每个设备都拥有一个唯一的设备码,并生成一个二维码,登录用户扫描二维码进行授权(微信硬件方案)
以方案一为例模拟请求:
获取 Device Code
POST Host: https://authorization-server.com response_type=device_code client_id=s6BhdRkqt3
请求响应如下:
{ "verification_uri": "https://authorization-server.com/authorize", "user_code": "94248", "device_code": "74tq5miHKB", }
-
user_code: 用户在通过授权服务器身份验证后应输入的代码。
轮询获取认证信息
https://authorization-server.com?grant_type=device_code&client_id=s6BhdRkqt3&code=74tq5miHKB
如果用户成功在 verification_uri 中填写 user_code(94248),则授权成功,返回:
{ "access_token": "2YotnFZFEjr1zCsicMWpAA", "expires_in": 7200, }
这时就可以通过 access_token 去访问用户信息。
对于微信二维码方案感兴趣的可以看这里 微信硬件平台
实际场景中的优化
在我们日常生活中,登录一个网站,如果使用 QQ 登录,最常见的方式就是扫码登录和开速登录。
其实扫描登录和快速登录本质都是 Authorization Code 模式,只是获取 Authorization Code 的方式由跳转到授权页面填写账号密码认证,改为了扫描二维码或点击头像。
扫码登录
一般扫码登录实现的大致流程如下:
-
客户端应用到授权服务器请求生成二维码,该二维码有唯一标识
-
用户使用 App 扫描该二维码,并授予权限,将授权信息更新至授权服务器。
-
客户端轮询授权服务器,查看是否有本次授权认证的信息
-
若有授权信息,则获取到对应的 Authorization Code
快速登录
这里的快速登录指的是网站中点击 qq 头像登录网站的场景
旧方案:Activex 控件
新方案:本地建立了一个服务器,并绑定了127.0.0.1,然后使浏览器访问本地服务器进行实现
在进入授权页面时,后发送下面请求,获取登录用户信息
https://localhost.ptlogin2.qq.com:4301/pt_get_uins?callback=ptui_getuins_CB&r=0.5293718898828204&pt_local_tk=-1936062636 response [{"account":"xxx","face_index":477,"gender":0,"nickname":"xxx","uin":"xxx","client_type":66818,"uin_flag":8388608}];ptui_getuins_CB(var_sso_uin_list);
点击头像后 set cookie
set-cookie: pt2gguin=;Expires=Thu, 01 Jan 1970 00:00:00 GMT;Path=/;Domain=qq.com; set-cookie: pt2gguin=o1009667841;Expires=Tue, 19 Jan 2038 03:14:07 GMT;Path=/;Domain=ptlogin2.qq.com; set-cookie: p_uin=o1009667841;Path=/;Domain=graph.qq.com; set-cookie: pt4_token=5RUGUJKbh38CkDUSxBeNLfOqwUFPc82sloYx4KaC02o_;Path=/;Domain=graph.qq.com; set-cookie: p_skey=NYihJaXr0xRafRW3pPJn7b3I*C7zlccGVLGrVBiykJE_;Path=/;Domain=graph.qq.com; set-cookie: p_uin=;Expires=Thu, 01 Jan 1970 00:00:00 GMT;Path=/;Domain=qq.com; set-cookie: p_skey=;Expires=Thu, 01 Jan 1970 00:00:00 GMT;Path=/;Domain=qq.com; set-cookie: pt4_token=;Expires=Thu, 01 Jan 1970 00:00:00 GMT;Path=/;Domain=qq.com;
然后获取请求授权服务器获取 code
https://graph.qq.com/oauth2.0/authorize ## Form Data response_type: code client_id: 100490701 redirect_uri: https://www.zhihu.com/oauth/callback/qqconn scope: get_user_info,get_info,add_t,add_pic_t,get_other_info,get_fanslist,get_idollist,add_idol,add_share state: 64343661316530622d356236392d346562322d383466372d373034313366626536303036 switch: from_ptlogin: 1 src: 1 update_auth: 1 openapi: 80901010 g_tk: 2075792225 auth_time: 1553704726002 ui: 5B871532-796A-47BF-9063-3A55B87A2CE0
最后 redirect Url 中包含了 code 信息
https://www.zhihu.com/oauth/callback/qqconn?code=FF8BCBE83FE20717A0BE63F4D07E40BD&state=64343661316530622d356236392d346562322d383466372d373034313366626536303036
获取到 code 之后,就是我们熟悉的 OAuth2.0 协议流程了。
总结
本文主要介绍有关第三方登录及 OAuth2.0 的一些基础知识。大家感兴趣的话可以点击下面的参考链接进行更深入的了解。
本文参考:
OAuth 2.0
OAuth 2.0 Authorization
维基百科
腾讯开放平台
微信开放平台
反向工程解析QQ扫码登录的OAuth2流程
QQ快速登录协议分析以及风险反思
全文完
以下文章您可能也会感兴趣:
-
分布式锁实践之一:基于 Redis 的实现
我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。
杏仁技术站
长按左侧二维码关注我们,这里有一群热血青年期待着与您相会。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。