现在网络的资料到处都是,很容易搜索到自己想要的答案。但答案通常只能解决自己一部分的问题。如果自己想要有一套自己的解决方案,还得重新撸一遍靠谱。

我需要学下OAuth2.0吗?

没看之前以为OAuth2.0是登录认证授权的东西,自己的项目里应该是需要的。实际上OAuth是为了第三方应用访问我们资源用的,大多数开发者基本不会用到这个东西。对于自己应用的认证授权,还是基于拦截器的token,SpringSecurity即可。只有做平台级别,像微信,微博,github这种级别才会用到。而真到那个时候,再看也行,也通常不会是你来做。简而言之,非必须。

接下来,我将从几个方面了解和学习使用OAuth2.0。对不对就不管了,反正我也几乎不会用到。ps.有个项目用到了,所以才会有本文。

  1. OAuth2.0介绍和功能
  2. 微信开放平台和github的OAuth2.0接入应用
  3. 自己写一个OAuth2.0服务
  4. Springboot OAuth2.0集成

快速了解OAuth2.0

资源很多,看起来比较麻烦,可以直接看Authorization Code授权码流程,以微信登录为例子的介绍。

OAuth2.0是什么

官方介绍是: OAuth 2.0授权框架允许第三方应用程序通过协调资源所有者和HTTP服务之间的审批交互,或允许第三方应用程序自己获得访问权限,从而获得对HTTP服务的有限访问。也就是授权别人(client)访问我们的资源

The OAuth 2.0 authorization framework enables a third-party

application to obtain limited access to an HTTP service, either on

behalf of a resource owner by orchestrating an approval interaction

between the resource owner and the HTTP service, or by allowing the

third-party application to obtain access on its own behalf.  This

specification replaces and obsoletes the OAuth 1.0 protocol described

in RFC 5849.

别人(client)是什么?

登录石墨文档可以输入账号密码登录,也可以选择微信登录,微信扫码确认后,就登录了石墨文档。石墨文档通过微信认证的方式实现了自身的认证登录。这个石墨文档就是client的角色(Role)。

什么时候需要让别人(client)访问我们的资源?

最常见的是微信授权登录,对client来说,是用户授权client拿到用户在微信上的信息,比如性别,唯一id。

我们怎么才能做到授权给别人访问我们的资源

我们自己怎么获取自己的资源?我们登录后就可以获取到自己的账号信息等资源了。那么怎么给到别人?直接把我们的账号密码给第三者太不安全了。一个是自己的账号密码存在泄露的风险,一个是自己的账号权限太大,万一被别人删除了或者看到了不该看到的东西怎么办。在使用阿里云的时候,我们可以给自己的账号开子账号,给子账号一些权限访问哪些服务(授权太复杂了),这样我们就可以达到最初的目的了: 让别人安全的访问我们的资源。

OAuth通过引入授权层并将client的角色与资源所有者的角色分离, 并且给client单独的凭证(access_token),client通过access_token获取有限的资源。

OAuth2.0定义的角色

resource owner

资源的拥有者,通常就是用户,比如登录的用户。

resource server

资源服务,提供资源的服务。需要access_token才允许被调用。比如微信api,通过access_token调用它可以获取到用户的性别等信息。

client

客户端,第三方客户端,被授权访问的应用。比如石墨文档通过微信登录的时候,石墨文档就是client角色,它要用户授权获取用户微信的信息。

authorization server

资源认证授权服务。用户登录到本服务后,可以选择授权给第三方。比如微信登录,微信认证服务就是authorization server的角色。可以颁发给client code,可以通过code换取access token. 可以通过access_token认证用户。

乍一看可能有点迷乱。站在登录用户的角度,简单的分为3个阵营: 用户本身(resource owner), 用户要登录的应用(client), 用户的资源(resource server and authrization server). authorization server和resource server是一体的,一家的,比如都是微信的。这样清晰一些。只是对于微信内部,个人信息,朋友圈,公众号,小程序啥的,资源挺多,相当于多个resource server, 内部就分成了authorization server和多个resource server.

搞清楚这里面的角色后,再来看协议的流程。

OAuth2.0的协议流程

整体抽象协议流程如下。

  • A: client找用户(resource owner)请求授权,说你得让我获取你的微信昵称. 然后用户就看到微信授权页面(authorization server)显示是否允许client获取昵称。
  • B: 用户点确认,微信就会给client一个临时授权code。
  • C: client拿着上一步得到的授权code去找authorization server换一个access_token.
  • D: authorization server认证了client的参数,确认后,给client返回access_token.
  • E: client拿access_token去获取信息,比如获取用户昵称,头像。
  • F: client如愿以偿。

直接看上面的图,看到B和C都特么叫Authorization Grant, 授权发放。一会儿用户给client发放,一会儿client又找authorization发放,这是要哪样。我当年就是看了无数次这个图没看懂。接着,一般的文章又会介绍OAuth2.0的4种授权方式,结合上图的授权,就会非常容易混淆,看不懂了。

官网描述授权发放:

An authorization grant is a credential representing the resource

owner's authorization (to access its protected resources) used by the

client to obtain an access token.  This specification defines four

grant types -- authorization code, implicit, resource owner password

credentials, and client credentials -- as well as an extensibility

mechanism for defining additional types.

授权发放模式是指client获取access_token的方式。官方给了4种,

  • authorization code: 授权码
  • implicit: 隐藏式
  • resource owner password: 用户的账号密码方式
  • client: client的id认证方式
  • 当然,也可以自由扩展,能认证返回access_token就行。

grant是指授权给client,4中授权模式对应的是上图的BCD,即获取access_token的过程有4种方式。

access token存储方式?

access token就是访问资源的凭证,令牌。它的安全很重要。为了防止泄露被窃取,通常是client后端服务用token获取资源,是存储在client后台服务的,比如redis,mysql中,和用户关联存储。在浏览器上是体现不出的。那中间人就不能网络拦截到token。即access_token不应该在浏览器访问网络中出现

以下用石墨文档(client)采用微信(authorization server & resource server)登录的方案来描述理解4种授权方式。

Authorization Code授权码

authorization code就不翻译了,代码里也是这么写的,翻译了就可能对不上了。这种方式获取token,首先用户让微信给一个code给client。client拿着code找微信换一个access_token,以后就用access_token获取用户的唯一id。

这个图对象比较多。先认识对象,微信用户(resource owner),浏览器,石墨文档(client),微信开放平台(authorization server),微信api(resource server)。

首先,石墨文档(client)需要在微信开放平台(authorization)注册,获取appId和appSecret. 这组凭证是石墨自己访问微信开放平台的。access_token则是代表用户本人,注意区别。

1.微信用户通过浏览器访问了石墨文档,然后登陆页,然后点了微信登录按钮

这时候,浏览器请求石墨微信登录回调地址,石墨后台返回302,response附属location. 浏览器重定向跳转到微信二维码认证页面。

https://open.weixin.qq.com/connect/qrconnect?appid=wx5a67899f4af8b0b1&redirect_uri=https%3A%2F%2Fshimo.im%2Flizard-api%2Fauth%2Fwechat%2Flogin_callback&response_type=code&scope=snsapi_login&state=740a608f-23b4-4abd-b941-e13d2b5c0dbe#wechat_redirect

注意几个参数:

  1. appid: 石墨文档作为client在微信开发平台的凭证id
  2. redirect_uri: 认证通过后,微信开放平台添加一个code参数到这个url后面,然后浏览器重定向到这个url。这个url是石墨文档后台接收code的接口。
  3. response_type: code。固定
  4. scope: 授权范围,想获取用户哪些资料的api。网页登录为snsapi_login
  5. state: 这个是防刷的,防止csrf跨站请求伪造攻击。微信认证成功后,回调的时候会原样返回给石墨(client)。如果没这个,client接收参数就只有code,别人就是随意伪造碰撞code。而石墨生成了一次性token作为state,回调接口只有一次有效期。这里石墨用的uuid.

2.用户微信扫描二维码,通过认证

用户微信点击了确认,就代表了授权通过了,允许石墨获取access_token. 浏览器微信二维码页面收到code,拼接redirect的url,浏览器重定向到石墨后台

https://shimo.im/lizard-api/auth/wechat/login_callback?code=081r8QFa1aYaRA03J7Ha1gUXl42r8QFk&state=740a608f-23b4-4abd-b941-e13d2b5c0dbe

这个回调地址code就是微信开放平台(authorization server)颁发给石墨文档(client)的code。

石墨文档后台接收到code和state后,校验state是否有效,然后拿code和appId,appSecret去访问微信接口获取用户信息。这一步是在石墨文档后台进行的。浏览器看不到access_token. 而对于上一步生成的code,即便有人拿到code,应该已经失效了。code和state都是一次性的有效期。这样保证了access_token的安全性。

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

返回:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

3.石墨文档获取到用户唯一id后,根据后台用户账号的绑定关系,确认当前登录用户登录


Implicit

Implicit翻译是隐藏式,这种针对纯web前端应用,没有后台,就没办法像上面一样了,令牌只能放在前端。这种也叫client side,又称为User Agent Flow,先说具体用法。

client直接请求authorization server获取access_token. 请求参数是client id和redirect url, 最后认证返回后拼接#access_code. 类似下图。

由于access_token网络传输,并不安全,很少使用这种方案。qq互联提供了一种,见 https://wiki.connect.qq.com/%e4%bd%bf%e7%94%a8implicit_grant%e6%96%b9%e5%bc%8f%e8%8e%b7%e5%8f%96access_token

1.请求认证的url参数: clientId, redirectUrI, Scope,state

  • client_id: 注册应用的 id,比如石墨文档在qq注册应用的appid
  • redirect_uri: 认证成功后要回调的地址,这个要和注册的时候一致
  • response_type: token
  • state: 同样的一次性随机数,会原样返回给client,防止csrf攻击。

2.认证成功后,回调地址中的access_token

qq认证成功后的示例:

http://graph.qq.com/demo/index.jsp?#access_token=FE04************************CCE2&expires_in=7776000&state=test

可以看到参数access_token是通过#传递的。这里涉及一个叫中间人攻击的安全问题,见http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html

注意,令牌access_token的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险

qq提示

可通过js方法:window.location.hash来获取URL中#后的参数值。

password

password需要用户把微信账号和密码给石墨文档,石墨拿着去微信换token,这种放弃看了,不可能给的,微信也不支持。

client

这种就是纯后台方案。client拿着client_id和secret去换access_token。通常就是我们后台服务调用的时候用到。比如使用aws的s3或者阿里云的oss上传文件。我们需要通过ak,sk认证,获取一个token,拿token去上传文件。这个流程写起来还挺麻烦的,一般都会封装好客户端给我们用。这里就不涉及用户了,只是客户端自己的认证了。

customize

自定义,我们也可以username + password登录走OAuth2.0校验。只是没client,或者说每个登录用户类似client。登录后返回access_token, 用户可以访问其他资源。

更新令牌

前面讲的4个授权方式,都是为了获取access_token。返回格式类似微信的:

{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

openid,unionid并不是必须的,这是微信认证用户的唯一的id。在微信的设计中,

  • access_token: 接口调用凭证,用来获取资源信息,比如用户的头像,昵称等。超时时间很短。微信设定为2h。
  • expire_in: access_token的超时时间,单位秒
  • refresh_token: 用户刷新access_token用的token。超时时间比较久。微信设定超时为30天,失效后需要用户重新授权。
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"
}

请求刷新token:

  • appid: client id,石墨注册在微信平台的id
  • grant_type: refresh_token固定
  • refresh_token: 上一步获取到的token

参考

OAuth2.0理解和用法的更多相关文章

  1. oAuth2.0理解

    转自http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 理解OAuth 2.0 作者: 阮一峰 日期: 2014年5月12日 OAuth是一个关 ...

  2. 深入理解OAuth2.0协议

    1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店 ...

  3. 帮你深入理解OAuth2.0协议

    1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店 ...

  4. 深入理解OAuth2.0

    1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店 ...

  5. 程序员的自我救赎---3.1:理解Oauth2.0

    <前言> (一) Winner2.0 框架基础分析 (二)PLSQL报表系统 (三)SSO单点登录 (四) 短信中心与消息中心 (五)钱包系统 (六)GPU支付中心 (七)权限系统 (八) ...

  6. 理解 OAuth2.0

    文章转载于阮一峰老师的博客:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 参考文章:https://learnku.com/article ...

  7. OAuth2.0深入理解

    1. OAuth2.0深入理解 1.1. 概念 OAuth(Open Authorization)开放授权,表示将系统功能部分授权给第三方系统调用,实现更细颗粒度的权限控制 OAuth是一种在线授权或 ...

  8. OAuth2.0的理解&基础

    此文章是复制黏贴网上文章的,主要做自己备用着看(也加了自己的一点见解),喜欢的读者也可以看. OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2 ...

  9. (转)帮你深入理解OAuth2.0协议

    1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店 ...

随机推荐

  1. NGK与AOFEX交易所达成战略合作,BGV即将上线A网!

    据NGK官方消息,NGK官方已经与英国伦敦知名交易所AOFEX交易所达成战略合作,将于12月2日全球首发BGV,现已开启充值服务.同时,在12月3日15:00,用户可以参与BGV交易:在12月4日15 ...

  2. 关于Python 编码的一点认识

    在计算机中,所有数据的存储.运算以及传输都必须是二进制数字,因为计算机只认识0和1. 当一个人把一份数据传给另一个人时,计算机传递的是其实是二进制数字,但这些数字需要被还原为原始信息. 这个工作当然是 ...

  3. HQYJ嵌入式学习笔记——C语言复习day2

    1.计算机的数值表示 数值类型和非数值类型 二进制 0,1 (0b1001) 八进制 0~7   (0146) 十进制 0~9 十六进制 0~f (0x3f) 八进制转二进制-->一位八进制数换 ...

  4. 推荐一款好用的免费远程控制软件——ToDesk

    创作立场声明:我在本文中评测的软件为自用,感觉不错并且全免费,第一时间发出来和大家分享,欢迎理性观点交流碰撞. 疫情刚开始的时候,待在家里不能上班,但是还是有很多工作需要在线完成,常常需要跑回办公室拿 ...

  5. flask启动常见问题1:sqlalchemy.exc.ArgumentError: Mapper mapped class UserCode->data_system_user_email could not assemble any primary key columns for mapped table 'data_system_user_email'

    我的描述:当我编辑好flask以后,ORM映射数据库完成,启动项目时,发生现象: 解决: 看字面的意思是主键导致的错误,于是我查看了data_system_user_email的键参数配置,发现表没有 ...

  6. Vim的基本命令

    Vi vi的两种模式 ①commad命令模式:无法输入任何东西,需要按下i进入编辑模式 ②edit编辑模式:按下esc退出到命令模式,在命令模式下按下wq [文件名] 可以退出并且成功的保存 //一些 ...

  7. Redis操作指南

    目录 Redis安装与使用教程 一.Redis介绍 1.redis安装 2.redis与mysql的异同 3.redis与memcache的异同 二.Redis操作 1.启动服务 2.密码管理 3.连 ...

  8. Linux关机指令详解

    Linux关机指令 在linux领域内大多用在服务器上,很少遇到关机的操作.毕竟服务器上跑一个服务是永无止境的,除非特殊情况下,不得已才会关机. 正确的关机流程为:sync > shutdown ...

  9. 判断app是否安装

    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.fromPar ...

  10. 使用jsoup十分钟内掌握爬虫技术

    对,就是十分钟,没有接触过爬虫的你,肯定一脸懵逼,感觉好高深的样子,一开始我也有点懵,但用了以后发现还是很简单的,java爬虫框架有很多,让我有种选择困难症,通过权衡比较还是感觉jsoup比较好用些, ...