# 身份验证
# 概述
身份验证为应用 web 系统提供了获取正在访问学加家的用户身份的能力,便于应用 web 系统构建登录流程。
# web端授权流程
- 用户点击三方应用入口(菜单或图标),前端容器使用iframe形式加载三方应用URL并携带SchoolID。
- 如果三方应用需要获取当前登录用户信息则需要发起用户授权(拼装授权URL并跳转至授权页面,默认静默授权)进入授权页面后检测当前用户登录状态(通过本地token获取当前用户预授权码)如果状态正常则返回三方redirect URL并携带当前用户预授权码(code)(如本地token失效则触发登录逻辑)。
- 三方应用通过预授权码与SchoolID等参数通过开放平台接口获取access_token和用户信息,并自行保持用户登录状态。
# 移动端授权流程
- 用户点击三方应用入口(菜单或图标),移动端容器使用web-view形式加载三方应用URL并携带SchoolID。
- 如果三方应用需要获取当前登录用户信息则需要发起用户授权(拼装授权URL并跳转至授权页面,默认静默授权)进入授权页面后检测当前用户登录状态(通过web-view jssdk 获取 token并获取当前用户预授权码)如果状态正常则返回三方redirect URL并携带当前用户预授权码(code)(如本地token失效则触发登录逻辑)。
- 三方应用通过预授权码与SchoolID等参数通过开放平台接口获取access_token和用户信息,并自行保持用户登录状态。
# 流程图
# 根据预授权码获取access_token
# 请求路径
https://auth.xuejj.com/oauth/token
# 请求方式
POST
# 请求header
字段名称 | 字段值 | 字段表述 | 是否必填 |
---|---|---|---|
Authorization | 值=Basic + 空格 + base64(appId:appSecret) | 是 | |
Content-Type | application/x-www-form-urlencoded | 固定值 | 是 |
User-Type | op | 固定值 | 是 |
Authorization的value由三部分组成:1.Basic, 2.空格,3.base64编码后的(appId:appSecret)
计算base64值的java代码如下:
byte[] toBytes = ("yourAppId" + ":" + "yourAppSecret").getBytes();
//appId使用base64的编码规则
String encoded = Base64.getEncoder().encodeToString(toBytes);
//这里就是Authorization的value,把三部分的字符串拼接起来
String headerValue = "Basic" + " " + encoded;
- 注意:appId与appSecret只是生成Authorization,不需要写入header
字段名称 | 字段值 | 字段表述 | 是否必填 |
---|---|---|---|
appId | 为isv分配的appId | 是 | |
appSecret | 为isv生成的appSecret | 是 |
# 请求Body
body使用表单方式提交
表单字段为
字段名称 | 字段值 | 描述 | 是否必填 |
---|---|---|---|
grant_type | password | 这里的值为固定值password | 是 |
username | 为预授权码code的值,注意code是一次性的,并且只有5到20分钟有效期。如果获取access_token失败,需要引导用户重新授权。 | 是 |
# 返回示例
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIxMzQ4NDYyMDMxMiIsImljb24iOiIiLCJhdXRob3JpdGllcyI6WyJ1c2VyIl0sImNsaWVudF9pZCI6InVjbSIsInJvbGVfbmFtZSI6InVzZXIiLCJ1c2VyX2lkIjoyNzUyMDIsInJvbGVfaWQiOiIxMTIzNTk4ODE2NzM4Njc1MjAyIiwiZXh0ZXJuYWxfdXNlcl9ubyI6IjI3NTIwMiIsInBob25lIjoiMTM0ODQ2MjAzMTIiLCJzY29wZSI6WyJhbGwiXSwic2Nob29sSWQiOjYxMDExMywibmFtZSI6IuWtmeeQpiIsImV4cCI6MTU5OTYyMjM5Mywic3lzdGVtX3NvdXJjZSI6Im9wIiwianRpIjoiYTJhNTQwMWItNWQwNC00MzgzLTljNTItZjk3YzExYzExMTVjIn0.p5eaPoz_zXTclPBNLyP-srIoWPPC7QroSsPMQDJITaTGsmP6CTJ_gNImew1AFiUVafmiZ12Z68JFixLxdBpFPfXkbXMrVKs2g-ZhqL4ITCsBTo7o4YiLAZ4wTSYe_sYPKEP_LggPOA8Bww60WjO-xipkzsrwdhpV_3aj1iJ6Eux-KKsR3SQ1tzHBSysvoE3NBxcQQ-lENOlWQUy1rHvwf4qiCEs-CAmeT7nnLKRjZtaQoTfb3pq-CgXKTSgbJGl66cfqyU74o0lziZ2fsLCzkUdbDo8pnRItd3ciJ88F5i3kZstDaD9SRMczA9Jmm52SC6ZpYQnOY5_7UJ3o6ik9-Q",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIxMzQ4NDYyMDMxMiIsImljb24iOiIiLCJhdXRob3JpdGllcyI6WyJ1c2VyIl0sImNsaWVudF9pZCI6InVjbSIsInJvbGVfbmFtZSI6InVzZXIiLCJ1c2VyX2lkIjoyNzUyMDIsInJvbGVfaWQiOiIxMTIzNTk4ODE2NzM4Njc1MjAyIiwiZXh0ZXJuYWxfdXNlcl9ubyI6IjI3NTIwMiIsInBob25lIjoiMTM0ODQ2MjAzMTIiLCJzY29wZSI6WyJhbGwiXSwic2Nob29sSWQiOjYxMDExMywiYXRpIjoiYTJhNTQwMWItNWQwNC00MzgzLTljNTItZjk3YzExYzExMTVjIiwibmFtZSI6IuWtmeeQpiIsImV4cCI6MTYwMDEzODc5Mywic3lzdGVtX3NvdXJjZSI6Im9wIiwianRpIjoiYTU2M2EzNmQtMzU0NC00NDFjLWE2ZjgtODhlZjExOWY3ZWQzIn0.TP37P6OuxAG0UVsSB4vqHfmlz4eWLYg7z-TxM3DL8wBhp-jXCyK99Y0XpW-8wvg47h2EQ0y5bhq6w8Qvuj8OoYU5s0VTakCnOKwQQ_CY0enT2GqQmXvd-A26Lqzm1ReTaTe1ebh_HAeWEs7m0dkveoU69yawjjk1wgLciEa3hHYYR8hFdrZKW9vPHsVNQJkpNqUNmbDDIURXHevBMzZCKex9IwbDsfNDcXVZ7yWAx8XhTpX7030VASVR_Q8_HD_wnTllKq8M0CcmdTF_kxeTDeenc7E89G1GcCxoQBh_JF8THFRbG9-M16ObC7qbxoDs-zv-AY9hUdvIjmlhdVWSVA",
"expires_in": 3600,
"role_name": "openapi",
"user_id": 275xxx,
"role_id": "1123598816738675202",
"external_user_no": "275202",
"phone": "134846xxx",
"schoolId": xxx,
"name": "xxx",
"icon": "",
"system_source": "op",
"app_id": "your_app_id",
"jti": "a2a5401b-5d04-4383-9c52-f97c11c1115c"
}
# 获取用户信息
access_token是标准jwt格式,可以通过解析access_token来获取用户的基本信息。为确保用户信息的可靠,必须使用以下公钥来解析jwt
# 公钥
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGmHv9bVGTLa3a3K6z0XxzttmNxwzAr6ECnbEpwysLCPgNNSgyIgquv2mo0+KkZJlajhAj4gX/qoJM5HaI98kB8gt05JO0alk1oVLHNg8rDEvFp/gedzRayJiLr+C+LT9k4Su9C0RlGlJ7jh6pJbIa5OTQFA+7mEqfipVXyP5x+SjjNN4nETfh+5t7vuxhzIefxgLUjWaWMc/pSFDTEvIvI0B0I6yAXwS1/K5hWpDx9qP6bH/AuTAG8eqG+uHP145WPy98uTPd0BF5JLqtl5j+a+15nlIMWvK5sTe9x+NyD03lfxUmurXtU7FXUSSrHpBNAumrMD1gaqJBomUqwl2wIDAQAB
-----END PUBLIC KEY-----
# 解析jwt的java示例代码如下:
/**
* 注意,这里使用使用了jjwt库来解析jwt,
* 更多使用请参考https://github.com/jwtk/jjwt
*
*/
public static Claims parseJWTUsingPubKey(String accessToken) {
String PUB_KEY_STR = loadPubKey();
Objects.requireNonNull(jsonWebToken, "accessToken is null");
try {
java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
new BASE64Decoder().decodeBuffer(PUB_KEY_STR));
java.security.KeyFactory keyFactory;
keyFactory = java.security.KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(bobPubKeySpec);
return Jwts.parser()
.setSigningKey(publicKey)
.parseClaimsJws(jsonWebToken).getBody();
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
return null;
}
}
# Claims里面包含的字段为
字段名称 | 说明 | 描述 | 备注 |
---|---|---|---|
userId | 用户id | 学加家中用户的唯一凭证,不为空 | |
name | 用户称呼 | 用户称呼,可能为空 | |
icon | 用户头像 | 有可能为空 |