OAuth2
认证协议
我们支持通过 OAuth2
的授权码模式来实现用户身份认证的过程,详见 RFC6749-section-4.1
使用授权码模式,将先通过一次用户的身份认证与授权,经用户确认后方能获得 token
。
在 OAuth2 协议时,平台已经实现了与学校统一身份认证系统,企业微信的集成对接,并且自动根据环境判断认证方式。因此通过授权码模式对接的应用,在浏览器上访问时,将通过统一身份认证系统认证,在微信/企业微信内打开时,则将自动通过企业微信认证。一次对接即可打通两个平台。
OAuth2 Endpoints
- Authorization Endpoint: https://api.ecnu.edu.cn/oauth2/authorize
- Token Endpoint: https://api.ecnu.edu.cn/oauth2/token
- Userinfo Endpoint: https://api.ecnu.edu.cn/oauth2/userinfo
- Logout Endpoint: https://api.ecnu.edu.cn/user/logout
认证流程
当集成身份认证时,采用的即为 OAuth2.0 授权码模式的认证流程,详见[RFC6749-section-4.1,流程大抵如下:
- a) 用户访问客户端,客户端将用户导向认证服务器。
- b) 用户进行身份认证,并选择是否给予客户端授权。
- c) 假设用户给予授权,认证服务器先生成一个授权码(code),并返回给用户,认证服务器将用户导向客户端事先指定的“重定向URI”(redirect uri),同时附上一个授权码(code)。
- d) 客户端收到授权码,附上早先的“重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
- e) 认证服务器核对了授权码和重定向URI,确认无误后,向客户端返回访问令牌。
- f) 客户端可解析令牌中的
id_token
数据获取用户名信息,或者使用令牌中的access_token
调用用户信息的相关接口,以获得更多用户相关信息。
a-c) 发起认证请求
用户侧发起请求,重定向到认证服务的 Authorization Endpoint(即 https://api.ecnu.edu.cn/oauth2/authorize) ,并携带相关参数
请求参数和示例
参数名 | 是否必填 | 备注 |
---|---|---|
response_type | 是 | 必须是 code |
redirect_uri | 是 | 期望的回调地址 |
scope | 是 | 统一为 ECNU-Basic |
client_id | 是 | 所分配的client_id |
state | 否 | 随机数,预防 cors 攻击,建议加上 |
https://api.ecnu.edu.cn/oauth2/authorize?scope=ECNU-Basic&redirect_uri=https://developer.ecnu.edu.cn/playground/authorization_code/callback&response_type=code&client_id=c99********1394d&state=92176092
认证授权
用户会被引导到统一身份认证,完成认证以后会触发授权。
符合以下情况,则该授权页面不会弹出
- 用户已经授权且记住了授权结果
- 应用没有申请任何接口权限(即仅通过
id_token
解析用户名,或者仅请求/oauth2/userinfo
接口获取用户名) - 应用被允许无需弹出授权页面
返回参数和示例
参数名 | 备注 |
---|---|
code | 所返回的 code |
state | 请求时附加的随机数,原样带回 |
https://developer.ecnu.edu.cn/playground/authorization_code/callback?code=c99********1394&state=92176092
d-e) 换取 Token
请求方法
POST
请求地址
https://api.ecnu.edu.cn/oauth2/token
请求参数
参数名 | 是否必填 | 备注 |
---|---|---|
grant_type | 是 | 必须是 authorization_code |
client_id | 是 | 所分配的 client_id |
client_secret | 是 | 所分配的 client_secret |
scope | 是 | 默认 ECNU-Basic |
redirect_uri | 是 | 重定向地址,必须和发起请求时的重定向地址一致 |
code | 是 | 上一步获取到的code |
返回参数
参数名 | 类型 | 备注 |
---|---|---|
token_type | string | token类型 |
access_token | string | 获得的 token |
id_token | string | jwt 的 id token |
expires_in | number | token 的有效期 |
scope | string | 默认为 ECNU-Basci |
refresh_toklen | string | refresh token |
请求示例
curl -i -X POST -d "code=37*****c077&redirect_uri=https://developer.ecnu.edu.cn/playground/authorization_code/callback&client_id=c99********1394&client_secret=12d***************c54&scope=ECNU-Basic&grant_type=authorization_code" "https://api.ecnu.edu.cn/oauth2/token"
返回示例
{
"access_token": "d14074bc99ac53e2722d29e1792af793",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJkOTZlODQ5MzE1NGRmYWJjIiwiZXhwIjoxNjIzMzA2Njg0LCJpYXQiOjE2MjMyOTk0ODQsImlzcyI6IkVDTlUtQmFzaWMiLCJzdWIiOiIyMDE1MDA3MyJ9.UQdA6RJh6iCxuflCXdaGGO1J2f-LqA7J8v4zFUSKIPZhzhlGZBcDFqYuQ9WGJuRIshuLAeeiLT4Qyhc831Xe5Dv_IK6ROMnU0Fp9q35tvPg4LbAuJkDdLpA74gIifAU-Av7g-3ITdgNNMIerEBpdbZl4YF2U9j8bL4_NjzH-nvKB6J-EFNjLGGyPswlCXiYsBau4Y-7z3GZebxOnBQOcCXd_yRWx5403hl8sSfQMCH6tBMQoZIqbkdsy89q3p2_MCAK46LwuojuQL9E89YD7aBBgw0EkO9dGBv_7Qv2vQpiMsCivhpuOMHzQDnqxNQmXbdlLE2SGX9zrNqhnkMJ7dw",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "ECNU-Basic",
"refresh_token": "5945d98c447132400033f9305efdb1c5b96d48bb3dca979b269536bf0d0e2732"
}
f) 获取用户信息
获取到 token 以后,客户端再进一步获取用户信息。例如通过解析 id_token
获取用户名。或者请求具体的用户信息接口即可。
身份令牌
我们在身份认证协议中,部分支持了 OpenID Connect 协议。token 中返回的 id_token
,身份令牌,也就是 ID Token 是由身份认证服务返回的,包含用户基本信息的 JWT 令牌。
身份令牌的 payload 主要构成部分如下:
{
"aud": "c99909106af1394d", // client_id
"exp": 1623301919, // 到期时间
"iat": 1623294719, // 签发时间
"iss": "ECNU-Basic", // Scope,目前都是 ECNU-Basic
"sub": "20150073" // 所认证的用户名
}
请求用户信息
OAuth2 服务默认提供了两种风格的 userinfo
接口,以获取最基本的用户信息,其包含以下字段内容。
字段 | 类型 | 说明 |
---|---|---|
userId | string | 用户的学号 |
name | string | 用户的姓名 |
vpnEnabled | number | 用户是否具备 VPN 权限,1 表示具备,0 表示不具备 |
接口支持 Authorization: Bearer
或者 url query
两种形式的 token
鉴权模式,详见使用令牌调用接口 部分的相关说明。
如需获取更多的信息,则需要申请相关的数据接口。
https://api.ecnu.edu.cn/oauth2/userinfo
将提供一个带层级,含错误码的用户信息接口,其返回示例如下:
{
"errCode": 0,
"errMsg": "success",
"requestId": "d1e51040-415e-4fe7-9a70-12ccb0bece21",
"data": {
"userId": "20****3",
"name": "**",
"vpnEnabled": 1
}
}
https://api.ecnu.edu.cn/oauth2/userinfo/flat
将提供一个扁平的用户信息接口,其返回示例如下:
{
"userId": "20****3",
"name": "**",
"vpnEnabled": 1
}
注销
应用注销时,可以通过访问 https://api.ecnu.edu.cn/user/logout?redirect_uri=https://apphost/xxxx 实现单点登录的注销。接口将自动注销 OAuth2 服务与 CAS 服务的会话,并重定向到期望的回调地址 redirect_uri 上。
如果 redirect_uri 不存在,则用户注销后会跳转至 https://developer.ecnu.edu.cn/
回调地址 redirect_uri 的域名,必须与该应用授权的域名一致,否则将跳转至默认页面 https://developer.ecnu.edu.cn/
会话与用户授权管理
授权服务器提供 access_token 的令牌签发,并确保令牌签发的过程中有用户的认证授权确认。会话应由应用端自行维护管理。尽管我们在授权码模式中,集成了 CAS 认证协议,并与学校其他 CAS 集成应用相兼容并支持 SSO。但 SSO 的会话仍然应该与应用本身的会话相独立,已经完成认证的用户应该由应用本身会话管理,避免不必要的认证触发行为。
当应用的会话有效期比较长时,可能需要刷新 token 以重新获取用户信息,此时可以使用 refresh_token 来刷新 token。refresh_token 的有效期为1个月,因此应用的会话有效期不应超过1个月,即每个月至少用户需要登录一次,否则用户信息可能无法更新。
授权码模式的应用,可以申请用户授权状态管理的接口,从而自行修改或更新用户的授权状态。详见 应用管理 中用户授权状态相关的接口。