使用授权码流程进行身份验证
授权码模式是最常用的 OIDC 流程,本节介绍如何使用授权码流程执行身份验证。使用授权码流程时,所有令牌均从令牌端点返回。
授权码流程将授权码返回给客户端,然后客户端可以直接将其交换为 ID 令牌和访问令牌。这样做的好处是不会向用户代理和其他可能访问用户代理的恶意应用程序公开任何令牌。授权服务器还可以在将授权码交换为访问令牌之前对客户端进行身份验证。授权码流程适用于能够在自身和授权服务器之间安全地维护客户端机密的客户端。
流程简介:
1 三方应用发起授权请求
构造请求
请求方式:GET(HTTPS)
构造如下的链接,并让客户端跳转到这个地址来获取授权码。
HTTP/1.1 302 Found
Location: https://passport.cdisu.edu.cn/connect/authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
参数说明
| 参数 | 必须 | 说明 |
|---|---|---|
| client_id | 是 | |
| client_secret | 是 | |
| response_type | 是 | 返回类型,此流程应该是“code” |
| scope | 是 | 应用授权作用域。 |
| redirect_uri | 是 | 跳转回你的应用的地址,认证成功后会将授权码以URL query的形式发送到你设置这个地址,这个地址必须在申请接口的时候提供,否则系统会不允许向该地址回调。请使用urlencode对链接进行处理 |
| state | 否 | 你定义一个字符串,可以用于防范 CSRF 攻击,如果返回的值和发送请求之前设置的 state 值不同,说明受到攻击。长度不可超过128个字节 |
2 用户登录
发起登录之后,如果用户先前未登录过,则会将用户重定向到登录页面,引导用户完成在认证。
验证通过后会将浏览器重定向到发起授权登录请求时指定的 redirect_uri 并通过 URL query 传递授权码 code 参数。
3 返回授权码
网关将以URL query的形式返回授权码,请你在应用内接收。
返回示例
HTTP/1.1 302 Found
Location: https://app.example.com/callback?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
参数说明
| 参数 | 说明 |
|---|---|
| code | 受权码,用于下一步获取访问令牌 |
| state | 应该与你授权请求所构造的的 state 值相同 |
4 三方应用发送令牌请求
构造请求
请求方式:POST
请求地址:https://passport.cdisu.edu.cn/connect/token
参数说明
| 参数 | 必须 | 说明 |
|---|---|---|
| Content-Type | 是 | 请求的 Header值Content-Type 项应为“application/x-www-form-urlencoded” |
| client_id | 是 | 应用 ID |
| client_secret | 是 | 应用 Secret |
| grant_type | 是 | 些流程应该为 “authorization_code” |
| redirect_uri | 是 | 发起 OIDC 授权登录时的 redirect_uri 值,必须与发起登录请求时的参数一致 |
| code | 是 | 获取到的授权码,一个 code 仅限一次性使用,用后作废,有效期 10 分钟 |
请求示例
curl --location --request POST 'https://passport.cdisu.edu.cn/connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'code=61yhuOVrgyhKlFTU~bnEKA_fnnz' \
--data-urlencode 'client_id=5e37979f7b757ead14c534af' \
--data-urlencode 'client_secret=64b517f8de3648091654eb4ee9b479d3' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'redirect_uri=https://yourApp/callback'
5 返回访问令牌
返回示例
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhVrj6W0eyo_e....",
"expires_in": 3597,
"refresh_token": "DuSPlrUFPAvCZ1WQKarv5MbEsXN",
"scope": "openid profile email",
"token_type": "Bearer"
}
参数说明
| 参数 | 说明 |
|---|---|
| access_token | 访问令牌 |
| expires_in | 有效时间(秒) |
| refresh_token | 刷新令牌,用于在访问令牌过期时重新获取访问令牌 |
如果需要,请参考 如何验证 Token 合法性
6 获取用户声明
开发者应该在自己的后端服务器使用 access_token 换取用户信息。如果发起授权登录时的 scope 参数不同,这里的返回信息也会不同,返回信息中的字段取决于 scope 参数。字段符合 OIDC 规范,用户信息字段与 scope 对应关系请参考 scope 参数对应的用户信息。
构造请求
请求方式:GET(POST)
请求地址:https://passport.cdisu.edu.cn/connect/userinfo
参数说明
| 参数 | 必须 | 说明 |
|---|---|---|
| access_token | 是 | 根据OAuth 2.0 Bearer Token 使用,从 OpenID Connect 身份验证请求获取的访问令牌必须作为 Bearer Token 发送。 |
请求示例
建议请求使用 GET方法,并使用Authorization标头字段发送访问令牌,
GET /connect/userinfo HTTP/1.1
Host: passport.cdisu.edu.cn
Authorization: Bearer {access_token}
返回示例
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub": "248289761001",
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe",
"preferred_username": "j.doe",
"email": "janedoe@example.com",
"picture": "http://example.com/janedoe/me.jpg"
}
参数说明
具体的用户声明和应用程序开发需求相关,不一定和示例完全一样。