看我就够了"/>
oauth 2.0 授权模式,看我就够了
oauth 2.0 是什么?
oauth 2.0 是一个授权的开放网络标准
角色
Resource Owner:资源所有者,既用户 User Agent:用户代理 Authorization Server:既提供第三方登录服务的服务器 Client:第三方应用,我们的应用就是一个client
客户端的授权模式类型
- 授权码模式
- 隐式授权模式
- 密码模式
- 客户端模式
授权码模式
+----------+| Resource || Owner || |+----------+^|(B)+----|-----+ Client Identifier +---------------+| -+----(A)-- & Redirection URI ---->| || User- | | Authorization || Agent -+----(B)-- User authenticates --->| Server || | | || -+----(C)-- Authorization Code ---<| |+-|----|---+ +---------------+| | ^ v(A) (C) | || | | |^ v | |+---------+ | || |>---(D)-- Authorization Code ---------' || Client | & Redirection URI || | || |<---(E)----- Access Token -------------------'+---------+ (w/ Optional Refresh Token)复制代码
1.授权请求 比如你想用登录gitlab,想利用三方授权登录,比如谷歌账号,当你点击谷歌图标的时候,会首先发起一个授权请求。 会带上以下参数,向授权服务器发送授权请求:
response_type:表示授权类型,必选项
client_id:表示客户端的ID,必选项,一般是在授权服务器上申请应用的时候,颁发的
redirect_uri:重定向的 uri
scope:表示申请的权限范围
state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回这个值
复制代码
下面是一个例子:
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example
复制代码
授权服务器验证该请求,确保所有的参数提交且有效,授权服务器会引导用户进入授权页面
2.当用户点击确定授权时,授权服务器会返回授权码(code)和状态参数(state),返回请求到相应的回调地址(redirect_uri)。至此,用户的主动行为已经结束。 3.第三方应用,也就是我们的客户端,在拿到授权码之后会直接向授权服务器请求访问令牌,参数如下:
grant_type:授权模式,必选项,值 "authorization_code"
code:从授权服务器收到的授权码
redirect_uri:回调地址
client_id:标识应用ID
client_secret:授权服务器颁发的密钥
复制代码
授权服务器验证通过后会返回如下参数:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{"access_token":"2YotnFZFEjr1zCsicMWpAA","token_type":"example","expires_in":3600,"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA","example_parameter":"example_value"
}
复制代码
至此整个授权码流程结束。
需要注意的几个问题
-
重定向 redirect_uri uri 整个授权过程都是一样的
-
授权过程只是授权: 比如,你想用 "支付宝" 授权登录 "优酷" ,整个授权的过程只是支付宝验证用户授权,返回一个 openId 和 支付宝允许给优酷的一些用户信息,优化拿到 openId可以直接上传服务端注册,至此整个授权流程结束。后面优酷相关联的资源获取和授权没有任何关联了。优酷会对这个 openId和账号做唯一映射,这样下次还用支付宝授权登录,优酷的服务端不会在创建新的账号给该用户,即不需要用户密码的一键登录。
-
为什么整个授权流程不直接返回 access_token 而是要经过中间步骤先要获取授权码 code ,在根据授权码再次获取 access_token ? 最直接的答案是安全,code有效期比较短,而且一个code只能换取一次access_token即失效。获取code的请求是用户主动授权之后获取的从这里截止,用户的主动行为结束。 获取参数不包含 appsecret,请求回来的code回立马再次发起请求,这次请求会带上appsecret,授权服务器验证并返回 access_token
隐式授权模式
+----------+| Resource || Owner || |+----------+^|(B)+----|-----+ Client Identifier +---------------+| -+----(A)-- & Redirection URI --->| || User- | | Authorization || Agent -|----(B)-- User authenticates -->| Server || | | || |<---(C)--- Redirection URI ----<| || | with Access Token +---------------+| | in Fragment| | +---------------+| |----(D)--- Redirection URI ---->| Web-Hosted || | without Fragment | Client || | | Resource || (F) |<---(E)------- Script ---------<| || | +---------------++-|--------+| |(A) (G) Access Token| |^ v+---------+| || Client || |+---------+
复制代码
和 授权码请求一样,首先你会发起一个授权请求,验证参数
- 授权请求:
response_type:表示授权类型,此处固定值为 token
client_id:客户端标识
redirect_uri:重定向 uri
scope:访问的权限范围
state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回
复制代码
客户端发起 HTTP 请求,如下:
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example
复制代码
2.授权服务器会验证该请求,确保所有的参数已提交且有效。授权服务器验证请求参数中的uri和客户端提交的重定向的uri保持一致。 如果,该请求是有效的,授权服务器验证对资源所有者进行身份验证并展示授权页面给用户。 用户同意授权请求时,授权服务器回返回如下参数:
access_token:授权服务器颁发的访问令牌
token_type:令牌类型
expires_in:过期时间
scope:表示授权权限范围
state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回这个值
复制代码
这些参数,拼接在重定向 uri 地址的后面
3.第三方应用向资源服务器发起请求,不包含上一步获取的access_token 资源服务器返回一个网页(通常是带有嵌入式脚本的 HTML 文档),其中的脚本可以提取出令牌,浏览器把access_token发送给客户端 至此整个简单授权模式结束。
隐式授权和授权码授权的区别就是,是直接获取access_token,不需要经过code步骤。但是获取的access_token需要资源服务器的脚本从第三方代理(既浏览器)中提取出来)发送给客户端。
密码模式
+----------+| Resource || Owner || |+----------+v| Resource Owner(A) Password Credentials|v+---------+ +---------------+| |>--(B)---- Resource Owner ------->| || | Password Credentials | Authorization || Client | | Server || |<--(C)---- Access Token ---------<| || | (w/ Optional Refresh Token) | |+---------+ +---------------+
复制代码
这种模式用户必须把"用户名"和"密码"给到客户端,客户端不得存储密码。这通常用在用户读客户端高度信任的情况下。
- 资源所有者像客户端提供他的用户名和密码
- 当发起请求客户端向授权服务器进行身份认证
- 授权服务器对客户端进行身份验证,验证资源所有者的凭证,如果有效则颁发访问令牌。
访问令牌请求参数:
grant_type:值必须为 "password"
username:资源所有者用户名
password:资源所有者密码
scope:客户端授权请求范围
复制代码
例如:
POST /token HTTP/1.1
Host: server.example
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
复制代码
授权服务器验证授权请求通过,参数如下:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{"access_token":"2YotnFZFEjr1zCsicMWpAA","token_type":"example","expires_in":3600,"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA","example_parameter":"example_value"
}
复制代码
客户端模式
+---------+ +---------------+| | | || |>--(A)- Client Authentication --->| Authorization || Client | | Server || |<--(B)---- Access Token ---------<| || | | |+---------+ +---------------+
复制代码
其实,这种模式不属于授权模式,是客户端的行为,而非用户行为 1.客户端向授权服务器请求验证,并要求一个访问令牌 2.授权服务器向客户端进行身份验证,如果有效,则颁发一个访问令牌
访问令牌请求:
grant_type:表示授权类型,值必须为 "client_credentials"
scope:客户端的授权请求反问
复制代码
如下,请求:
POST /token HTTP/1.1
Host: server.example
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
复制代码
授权服务器验证该请求,如果请求有效则返回,令牌:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{"access_token":"2YotnFZFEjr1zCsicMWpAA","token_type":"example","expires_in":3600, "example_parameter":"example_value"
}
复制代码
刷新访问令牌
如果,授权服务器颁发了刷新 refresh_token,可以在客户端发起刷新 access_token,一般 refresh_token有效期是大于access_token有效期 请求参数如下:
grant_type:授权类型,此处必须为 "refresh_token"
refresh_token:颁发给客户端的刷新令牌
scope:表示可访问的权限范围复制代码
如下 HTTP 请求
POST /token HTTP/1.1
Host: server.example
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
复制代码
更多推荐
oauth 2.0 授权模式,看我就够了
发布评论