oauth2的使用场景、常见误区、使用案例
本文如有不对之处,欢迎各位在评论区指出
OAuth2使用场景
蒋志予博士说过:
不要为了技术而技术,场景和落地才是关键
oauth2是一种很复杂的授权协议,我们首先必须了解它的使用场景,才能够更好的去使用它,切记不可为了技术而技术,合适的才是最好的。
OAuth2 的常见使用场景
- 三方登录:当你自己开发的网站需要引入微信、qq、支付宝、钉钉等第三方登录的时候
- 开放平台:例如一些物流需要开放一些接口,用来给第三方应用去查询相关的物流信息
- sso单点登录:微服务环境下sso相关场景
OAuth2常见误区
-
误区:认为 oauth2 与登录认证关系很大
oauth2 只是一个授权协议,跟认证没有太大的关系
-
误区:认为 oauth2 一定能做认证体系
oauth2 做认证体系的前提是必须提供用户信息端点 /userinfo
我这里个人理解就是你要引入的第三方登录平台必须开放它的个人用户信息库
-
误区:oauth2 的token作用域不能直接给前端
谁是客户端,谁就有资格去拿到 token
因为我们一般是在后台代码去请求授权服务器给一个 token,而对于谁在请求这个 token 授权谁就是客户端。所以一般我们后端就可以理解为 oauth 的客户端。
-
到底谁是 oauth2 的客户端
标准是唯一-的,谁在授权服务器注册谁就是 oauth2 客户端。例如我们上面所说的就是我们的后端服务器。
-
oauth2 scope 和 role的区别
我个人理解就是 scope 是服务器授权给我们的一些权限:例如gitee、github里赋予开发者维护仓库、推送代码、新建 和删除分支这些权限
而 role 就是我们自己用户的角色
-
User Agent(前端(web ios 安卓等)的载体) User Agent 是有标识的
User Agent本质上是我们的用户代理,它帮助我们跳转到授权页面进行授权相关的操作
-
如何在前后端分离模式下使用 oauth 协议:
由于oauth的原理是 User Agent 通过后端 302 重定向返回的地址去引导的,所以我们需要进行非常规处理才能实现
原因:User Agent 收到 302 指示后会去找到后端指定的 location 地址,然后User Agent会直接向 location 发出get请求,而前后端分离模式下 axios 302没有办法处理
-
前后端不分离模式下:response.redirect(“/login”)
-
前后端分离模式下:response.redirect(“https://yourdomain.com/login”)
以上两种都是正规方式
-
不正规的方式
response -> {code : 302 , location : “yourlocation”}
这是一种不安全的方式,因为这个需要我们程序员去编写前端代码去获取location的值,而前端的所有代码都是能够被直接获取的。
-
-
没有很大必要一定要在前后端分离模式下使用oauth协议
因为认证、授权服务器是一个基本组件,和我们的业务是分离的,没有必要为了前后端分离而加入跟多的代码
Keyloak 是目前最完善的 oauth2 授权服务器,它就是前后端不分离的。
通过案例透彻了解OAuth协议
背景
有一个名为“信用卡管家”(www.a.com)的程序,可以自动从网易云邮箱中读取与信用卡相关的邮件,然后进行分析、汇总后,形成一张报表。
密码
“信用卡管家”如何访问网易云邮箱?
- 用户直接把账号和密码输入,然后“信用卡管家”去读取网易云邮箱的内容
产生的问题?
- 存在信任问题:如果你只是一个小网站,用户不敢把这种很重要的账号和密码信息给你。
token
“信用卡管家”如何访问网易云邮箱?(可见下面整体流程)
- 登录界面提供新的入口,使用网易账号登录。点了之后,就会跳转到网易的认证系统进行登录,然后网易的认证系统需要你输入用户名和密码,并且询问你是否运行”信用卡管家“访问邮箱。
- 确认之后,就重定向到“信用卡管家”网站,并且携带一个token过来,就可以通过API来访问网易邮箱了。
- 整个过程中,不会涉及到用户名和密码。token是网易认证中心颁发的,实际上就代表了用户对信用卡管家访问邮箱的授权,所以有了这个token 就可以访问你的邮箱了
整体流程
网易怎么信任“信用卡管家”?
- 需要将“信用卡管家”去网易上注册一下,网易就会给“信用卡管家”发一个app_id和app_secret。重定向到网易时就需要将这些东西发过去,这样网易就知道”信用卡管家“这个应用在申请授权了
如何存储这个token?
-
浏览器保存token
-
通过hash fragment的方式,请求的时候带上这个token参数 例如:www.a.com/callback#token=<网易返回的token>”
为什么存储在客户端?
- 为了提高安全性:只会停留在浏览器端, 只有Javascript 能访问它,并且它不会再次通过http request 发到别的服务器器
疑问?图上第6步token以名文方式传输会存在安全问题,可以通过浏览器的历史记录或者访问日志能够获取。
授权码 + token
如何将token进行隐藏?
-
引入了一个叫做Authorization Code的中间层。 当用户用网易账号登录的时候, 网易认证中心这一次不给”信用卡管家“直接发token,而是发一个授权码(authorization code) ,
-
信用卡管家服务器端取到这个code以后,在后台再次访问网易认证中心, 这一次网易认证中心才发给”信用卡管家“真正的token 。
为何要这样设计?
- 通过返回的授权码在服务器后台‘偷偷地’完成申请token 的过程, 所以token浏览器端根本就接触不到
code也是明文传输,不也存在安全问题码?
- 授权码和信用卡管家申请的app_id,app_secret关联, 只有信用卡管家发出的token请求, 网易认证中心才认为合法; 还可以让授权码有时间限制,比如5分钟失效,还有可以让授权码只能换一次token, 第二次就不行了
总结
本文讲的其实就是就是OAuth 中的三种认证方式,依次是:
- Resource Owner Password Credentials Grant(资源所有者密码凭据许可)
- Implicit Grant(隐式许可)
- Authorization Code Grant(授权码许可)
还有一种叫做Client credentials ,用的较少,文章没有涉及。
在OAuth中,还有几个术语大家可以理解下:
- 资源所有者 : 就是上文中的用户
- 资源服务器 :即网易邮箱
- 客户端: 就是上文的信用卡管家
- 授权服务器 : 即上文的网易认证中心
参考资料:
码农小胖哥、《码农翻身》