本文内容来自王松老师的《深入浅出Spring Security》,自己在学习的时候为了加深理解顺手抄录的,有时候还会写一些自己的想法。
OAuth2简介
OAuth是一个开放标准,该标准允许用户让第三方应用访问该用户在某一个网站上存储的私密资源(如头像、照片、视频等),并且在这个过程中无须将用户的账号/密码提供给第三方应用。通过令牌(token)可以实现这一功能,每一个令牌授权一个特定的网站在特定的时间段内允许访问特定的资源。
OAuth让用户可以授权第三方网站灵活访问他们存储在另外一些资源服务器上的特定信息,而非所有内容。对于用户而言,我们在互联网应用中最常见的OAuth应用就是各种第三方登录,例如QQ授权登录、微信授权登录、微博授权登录等等。
例如,用户想要通过QQ登录今日头条,这时今日头条就是一个第三方应用,今日头条需要访问用户存储在QQ服务器上的一些基本信息,就需要得到用户的授权。如果用户把自己的QQ账号和密码告诉今日头条,那么今日头条就能访问用户存储在QQ服务器上的所有数据,并且用户只有修改了密码才能收回权限,这种授权方式安全隐患很大,如果使用OAuth协议就能很好的解决这一问题。
OAuth2的四种授权模式
OAuth2协议一共支持四种不同的授权模式:
- 授权码模式:常见的第三方平台登录功能基本都是使用这种模式
- 简化模式:简化模式是不需要第三方服务端参与,直接在浏览器中向授权服务器申请令牌(token),如果网站是纯静态的页面,则可以采用这种方式
- 密码模式:密码模式是用户把用户名/密码直接告诉客户端,客户端使用这些信息向授权服务器申请令牌(token)。这需要用户对客户端高度的信任,例如客户端应用和服务
- 客户端模式:客户端模式是指客户使用自己的名义而不是用户的名义向服务器提供者申请授权。但是,对于开发者而言,在一些为移动端提供的授权服务器上使用这种模式还是非常方便的
从图中我们可以看出OAuth2中包含四种不同的角色:
- Clinet:第三方应用
- Resource Owner:资源拥有者
- Authenorization Server:授权服务器
- Resource Server:资源服务器
授权码模式
授权码模式(Authorization Code)是最安全且使用最广泛的一种OAuth2授权模式,同时也是最复杂的一种授权模式,其具体的授权流程如下:
整个流程图看起来有点复杂,这里结合王松老师的一个案例来学习:假设现在想给www.javaboy.org这个网站引入Github第三方登录功能,如果使用OAuth2协议中的授权码模式,那么流程应该是这样的:
首先www.javaboy.org这个网站相当于一个第三方应用,该网站的首页上会放置一个登陆连接,用户(服务方的用户,这里指的是Github用户)单击这个连接,就会请求授权服务器(这里指的是Github授权服务器)。
www.javaboy.org网站首页的登录超链接可能是下面这样的:
https://github.com/oauth/authorize?response_type=code&client_id=javaboy&redirect_uri=www.javaboy.org&scope=all&state=123
这个连接中的参数比较多,我们一一解释下:
- response_type:该参数表示授权类型,使用授权码模式的时候这里固定为code,表示要求反馈授权码,拿到授权码之后,在根据授权码去获取AccessToken
- client_id:该参数表示客户端id,也就是第三方应用的id。这里是相当于Github来说的,需要到Github平台上去申请 (需要去Github平台去注册,注册地址:https://github.com/settings/developers)
- redirect_uri:该参数表示在登录校验成功/失败后跳转的地,即校验成功后,跳转到该页面。跳转的时候,还会携带上一个授权码参数,开发者在根据这个授权码获取AccessToken
- scope:该参数表示授权范围,即www.javaboy.org这个第三方应用拿到AccessToken能干什么
- state:授权服务器会原封不动的返回该参数,通过对该参数的校验,可以防止CSRF攻击
当用户单击登录超链接时,系统会将用户导入授权服务器的登录页 面;用户选择是否给予授权;如果用户同意授权,则授权服务器会将页面 重定向到redirect_uri指定的地址,同时携带一个授权码参数(如果一开 始的链接提供了state参数,这里也会将state参数原封不动返回);获取到的授权码,再结合自有 的client_id和grant_type、redirect_uri等参数,向授权服务器请求令牌, 这一步是在客户端的后端进行的,对用户不可见;授权服务器对参数进行校验之后,会返回Access Token和 Refresh Token。
这就是授权码模式的工作流程。一般认为授权码模式是四种模式中 最安全的一种模式,因为这种模式的Access Token不用经过浏览器或者 移动端App,是直接从项目的后端获取,并从后端发送到资源服务器 上,这样就很大程度上减少了Access Token泄漏的风险。
简化模式
对于没有后端只有页面的网站,如果想要第三方功能该怎么办呢?这就是该小结要学习的简化模式(Implicit),流程如下:
首先在www.javaboy.org网站上有一个Github第三方登录的超链接,这个链接如下:
当用户点击了登录超链接,系统会将用户导入授权服务器的登录页面。用户选择是否给与授权,如果用户同意授权则授权服务器会将页面重定向到redirect_uri指定的地址,同时在重定向的URL中添加锚点参数携带AccessToken,如下:
密码模式
使用密码模式(Password)有一个前提就是高度信任第三方应用,只有高度信任第三方应用,才可以让用户在第三方应用的页面上输入登录凭证。下图是密码模式的流程:
首先用户在第三方应用的登录页面输入登录凭证(用户名/密码)。第三方应用将用户的登录信息发送给授权服务器,获取到令牌AccessToken。授权服务器检查用户的登录信息,如果没有问题则返回AccessToken和RefreshToken。
客户端模式
有的应用可能没有前端页面,只有一个后台,这种时候如果要使用OAuth2,就可以考虑客户端模式(Client Credtials)。流程如下:
客户端模式的流程很简单,只有两个步骤:
- 客户端发送一个请求到授权服务器
- 授权服务器通过验证后,会直接返回AccessToken给客户端
由于客户端模式是以客户端的名义向授权服务器请求令牌,所以授权服务器的令牌AccessToken颁发给客户端而非用户。