Google OAuth Playground是个好东西啊。我觉得任何面向普通用户的产品都应该提供Playground,用简单的交互方式鼓励用户去学习和探索。
下面使用Google OAuth Playground来体验一下gmail。首先申请gmail的接口权限。scope里面我加了profile
。
发出去的请求和响应如下所示。可以看出scope是用户自己填写的scope加上接口对应的scope。
### request
HTTP/1.1 302 Found
Location: https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground
&prompt=consent&response_type=code
&client_id=407408718192.apps.googleusercontent.com
&scope=profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.labels
&access_type=offline
### response
GET /oauthplayground/?code=4/SgDEu1NXPFIatxEo50ZHnMlYAQni0lfUisoTiBuglhe7KgHt15yp6cmxDRmg7dXVNQ12TQVWf_iPMVhEwvhE6dg HTTP/1.1
Host: developers.google.com
接着通过code换取token。发出去的请求和响应如下所示。
### request
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-length: 277
content-type: application/x-www-form-urlencoded
user-agent: google-oauth-playground
code=4%2FSgD0q_95DH9rsflVye4fTYMRBFFtzT68gSzkzxckhutSZS336TnR2I8QClVtgUln4j0twpC0QY9xX0HBNCNdbvY
&redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground
&client_id=407408718192.apps.googleusercontent.com
&client_secret=************
&scope=
&grant_type=authorization_code
### response
HTTP/1.1 200 OK
Content-length: 328
X-xss-protection: 1; mode=block
X-content-type-options: nosniff
Transfer-encoding: chunked
Vary: Origin, X-Origin, Referer
Server: ESF
-content-encoding: gzip
Cache-control: private
Date: Wed, 29 Aug 2018 08:54:38 GMT
X-frame-options: SAMEORIGIN
Alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"
Content-type: application/json; charset=utf-8
{
"access_token": "ya29.GlsIBpjUVLlYP6GoqZQwnd8rpHCV7nhCUv9polPCckmHAN46tVxOq430KolLvwKrLS2Xe4ubD-N_upteTMSLATAYr8lRzygmhi4uGXGlIMh67FbzJ1UHdmcMMZYQ",
"scope": "https://www.googleapis.com/auth/gmail.labels",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "1/psE38HLjvwfQNYHsGR4S6ssDE6BlcLW0yYX7SgJ_SAI"
}
第三步是从List possible operations
里面选取自己要访问的服务。
这个https://www.googleapis.com/gmail/v1/users/{userId}/labels
接口可以获取到用户的自定义标签。唯一需要填写的是userId。那么userId是什么呢?这个时候又得用上 https://jwt.io 解开 id_token,其中的sub
就是userId啦。sub
的定义可以参看:JSON Web Token (JWT)。
可以看到成功获取到用户的自定义标签数据,非常棒。
OAuth 2.0标准将客户端分为confidential
和public
两种,其中confidential
客户端可以保证client_secret的安全性,因此可以使用Authorization Code Grant
。public
客户端没有条件保证client_secret的安全性,所以一般使用Implicit Grant
。
根据使用客户端的不同,应用可以分为web application
、user-agent-based application
和native application
三种,其中web application
是confidential
客户端,后两种则是public
客户端。web application
的逻辑在服务器端。user-agent-based application
是通过user-agent,比如浏览器,直接使用OAuth Endpoint。web application
和user-agent-based application
可能都是网页应用,但是采用不同的授权模式。native application
是native app,除非特别设计,要不然把client_scret保存在客户端是很危险的行为。
Google的文档:OAuth 2.0 for Client-side Web Applications 对于这几种应用的描述更加通俗易懂一些,比如Web Server Applications
是web application
,Client-side Web Applications则是user-agent-based application
。
Google OAuth Playground属于web application
,通过浏览器的开发者工具调试可以发现,它并不会直接跟Google OAuth相关的Endpoint打交道,而是使用自己服务器端的接口。
Google OAuth Playground虽然默认使用Authorization Code Grant
,但是Google OAuth Server也是支持Implicit Grant
的,指定response_type=token
就会使用Implicit Grant
。
//请求中指定response_type=token
https://accounts.google.com/o/oauth2/v2/auth?
redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground
&prompt=consent
&response_type=token
&client_id=407408718192.apps.googleusercontent.com
&scope=https%3A%2F%2Fmail.google.com%2Fmail%2Ffeed%2Fatom
//直接把access token返回回来了,有效期是一个小时,不会有refresh token。
https://developers.google.com/oauthplayground/#
access_token=ya29.GltTBKTMzaEUXE6A-8JwSDkeGsPchWpQ7w8Vwbme_dmIEuJWe_BxUboN7tL7W4d4NC7aYIPteQxal-Rh5ICLQVYxLXF8Yj651Qi-yHkKGpaALcnzdR_QTqiX7N5_
&token_type=Bearer
&expires_in=3600
输入上面的URL,用户完成登录并且在consent页面操作之后,会自动跳到Step 3.
Implicit Grant
默认不会返回Refresh Token,但是OAuth Playground在获取auth code的请求里面加上access_type=offline
,这样在换取的token的时候服务器端就会返回Refresh Token。