OAUTH2
基本角色定义
- 授权服务器 - 验证身份并颁发令牌的服务器(我上面代码示例中的OAuth服务器)
- 资源服务器 - 提供API资源的服务器
- 客户端应用 - 访问API的应用,可以是:
- 第一方应用 - 您公司自己的应用
- 第二方应用 - 业务合作伙伴的应用
- 第三方应用 - 外部开发者的应用
token 类型
- access_token (默认有效期 24 小时)
- refresh_token(默认有效期 30 自然日,每次刷新 access_token 的操作可自动刷新 refresh_token 有效期的起始计算时间)。
客户端凭证流程(适用于服务器到服务器通信)
1 2 3 4 5 6 7 8 9 10
| 第一方/第二方应用 授权服务器 资源服务器(API) | | | |---1. 请求访问令牌------------>| | | (使用client_id和client_secret)| | | | | |<--2. 返回access_token---------| | | | | |---3. 使用access_token调用API------------------>| | | | | |<--4. 返回API响应---------------------------------| |
|
这种流程中:
- 获取令牌方: 第一方或第二方应用直接获取令牌
- 使用令牌方: 同样的应用使用令牌调用API
- 无用户参与: 整个过程无需最终用户授权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 客户端 认证服务器 | | |------- POST /token ---------------->| | grant_type=client_credentials | | client_id=CLIENT_ID | | client_secret=CLIENT_SECRET | | | |<------ 200 OK JSON 响应 ------------| | { | | "access_token": "eyJhbGc...", | | "token_type": "Bearer", | | "expires_in": 3600 | | } | | | |------- 使用令牌访问API ------------>| | Authorization: Bearer eyJhbGc... | | |
|
授权码流程(适用于有用户参与的场景)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 用户 第一方/第二方/第三方应用 授权服务器 资源服务器(API) | | | | |----1. 访问应用---->| | | | | | | |<---2. 重定向到-----| | | | 授权服务器 | | | | | | | |----3. 登录并授权------------------------->| | | | | | | |<---4. 重定向回应用,携带授权码(code)------| | | | | | | |----5. 返回应用,----->| | | | 带上授权码 | | | | | | | | |---6. 使用code请求令牌---->| | | | (附带client_id/secret) | | | | | | | |<--7. 返回access_token-----| | | | 和refresh_token | | | | | | | |---8. 使用access_token调用API--------------->| | | | | | | |<--9. 返回API响应--------------------------------| | | | |
|
这里面有两次重定向:
第一次:重定向到授权服务器。用户是带着一个 param 去访问authserver的,在我们常见的场景里线索通跳到 sso 是第一次重定向,参数里带有 https://app.example.com/callback 就是授权完以后再回到线索通的一个 url。
- 当用户尝试访问需要授权的功能时,应用生成一个授权请求URL
- 这个URL包含redirect_uri参数(应用事先在授权服务器注册的URL)
- 应用通过HTTP 302重定向或者前端跳转,将用户浏览器导向授权服务器
1 2 3 4 5 6
| GET https://auth-server.com/oauth/authorize? response_type=code& client_id=CLIENT_ID& redirect_uri=https://app.example.com/callback& scope=profile email& state=random_state_value
|
第二次:重定向回应用,携带授权码(code)。
- 用户在授权服务器完成身份验证并授予权限后
- 授权服务器使用之前请求中的redirect_uri,将用户浏览器重定向回应用
- 重定向URL中附加授权码(code)作为查询参数
1 2 3 4
| HTTP/1.1 302 Found Location: https://app.example.com/callback? code=AUTHORIZATION_CODE_VALUE& state=random_state_value
|
- 授权服务器只会重定向到预先注册的URI,防止授权码被重定向到恶意网站
- 防止授权码被重定向到恶意网站
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| 用户/浏览器 客户端应用 认证服务器 资源服务器 | | | | | | | | | |-- 重定向用户认证 ->| | | | /authorize? | | | | client_id=...& | | | | redirect_uri=...& | | | | response_type=code| | | | | | |<-----------------|<-------------------| | | | | | |--- 登录界面交互 ->| | | | | | | | |<-- 重定向回客户端 --| | |<-- 重定向回 -----| /callback?code=.. | | | 客户端应用 | | | | | | | | |-- POST /token ---->| | | | grant_type= | | | | authorization_code| | | | &code=... | | | | &redirect_uri=... | | | | &client_id=... | | | | &client_secret=...| | | | | | | |<-- 返回令牌 -------| | | | access_token, | | | | refresh_token等 | | | | | | | |-------------------- 使用令牌访问资源 ----->| | | Authorization: | | | | Bearer {token} | | | | | | | |<------------------- 返回受保护资源数据 ----| | | | |
|
刷新令牌流程 (Refresh Token Flow)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 客户端 认证服务器 | | |------- POST /token ---------------->| | grant_type=refresh_token | | refresh_token=REFRESH_TOKEN | | client_id=CLIENT_ID | | client_secret=CLIENT_SECRET | | | |<------ 200 OK JSON 响应 ------------| | { | | "access_token": "NEW_TOKEN", | | "token_type": "Bearer", | | "expires_in": 3600, | | "refresh_token": "NEW_REFRESH" | | } | | |
|