开放接口说明

目录

1 开始开发

1.1 获取accessToken

accessToken是调用平台接口的唯一凭据,调用各接口时都需使用accessToken。accessToken的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的accessToken失效。接口地址:

http://open.csedu.gov.cn/open/api/accessToken?clientId=clientId&secret=secret

返回{"success":true, "result":"accessToken"}, 其中参数clientId和secret为第三方的唯一标识和凭证密钥,请和平台管理员联系获得。

1.2 返回值

返回值为JSON格式:
正常返回:{"success":true, "result":"业务返回值"}
错误返回:{"success":false, "code":1.3里的代码, "message":"业务返回的错误信息"}

1.3 错误码

代码 含义描述
0 默认失败
-1 client 不存在
-2 secret 验证失败
-3 openId不存在
-100 accessToken 无效
-101 授权 code 无效
-110 找不到对应学生
-111 找不到对应用户
-112 学校无修改记录
-9995 无效的授权回调域名
-9996 ip 无权限
-9997 无权限访问
-9998 系统内部错误
   

2 网页开发

2.1 网页授权

在访问第三方App网页时,第三方可以通过平台的授权机制,来获取用户的基本信息。授权分两步:跳用户授权页面->授权成功使用授权码获取用户信息。
网页授权是通过OAuth2.0机制实现的,直接使用accessToken和授权code来直接获取用户信息,code仅能使用一次,5分钟内有效。
此方式适用于PC端和微信端,会自动适配对应的授权页面,授权接口也保持完全一致。

2.1.1 用户登录后同意授权,获取code

首先引导用户访问

http://open.csedu.gov.cn/open/oauth2/auth?clientId=baidu&responseType=code&state=STATE&redirectUri=http%3a%2f%2fbaidu.com

用户同意授权后,页面将跳转至redirectUri?code=COCE&state=STATE

参数 说明 是否必须
clientId app唯一标识
responseType 返回类型,请直接填写"code"
state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
redirectUri 授权后重定向的回调链接地址,请使用urlEncode对链接进行处理

2.1.2 使用code获取用户信息

使用上一步获取的code,使用HTTP的post方式请求下面链接:

http://open.csedu.gov.cn/open/api/authCode?accessToken=token&code=CODE

其中accessToken来自于获取accessToken
返回格式见返回值,正常情况会返回:

{"result":{"openId":"MvdMCCpwpSMMifhwNJvpOadTREIpZbDDdCl4871o_b8=","nickName":"test","headImgUrl":"http://a-images.b0.upaiyun.com/upload/images/9992b465d45e4eef9960795fe7133614.png"},"success":true}

如果授权code无效时,返回:

{"code":-101,"success":false,"message":"授权code无效:dce25064e65"}

错误码详见1.3
业务返回用户信息字段描述:

字段 说明 是否必返回
openId 用户对外唯一标识
nickName 用户昵称
headImgUrl 用户头像

2.1.3 用户登出通知

上面两步是获取当前登录用户的授权, 当APP有和平台保持同步登出的需求时(类似单点登录),平台提供了异步消息通知来告知APP的后台当前用户已登出。
首先需要APP后台提供登出消息接收地址,如果用户使用网页授权访问了APP,在用户主动登出平台时,平台会把登出用户的openId发送到APP提供的地址。
平台会以头部信息Content-Type:"application/json;charset=UTF-8",把下面格式信息POST到提供的地址:

字段 描述 是否必需
toUser APP的clientId
type 此处会为"Logout"
body 业务信息加密,此处为{userOpenId:"openId"}加密
createTime 消息发送时间
sign 签名,方式见后
  1. body解密方式

    body为业务信息的json字符串以3DES加密后的BASE64编码,解码时对应先BASE64解码,再使用APP的secret进行解密。
    Java示例:

    /**
     * 先进行Base64解码,然后使用APP的secret进行3DES解密
     */
    public static String desedeDecryptFromBase64(String body, String appSecret) {
        try {
            Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            SecretKeySpec key = new SecretKeySpec(appSecret.getBytes(), "DESede");
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(decodeBase64(body)));
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            throw convertRuntimeException(e);
        } catch (Exception e ) {
            e.printStackTrace();
        }
        return null;
    }
    
    public static byte[] decodeBase64(String s) {
        return org.apache.commons.codec.binary.Base64.decodeBase64(s);
    }
    
    /* C# 示例 */
    public static string DesedeDecryptFromBase64(String body, String appSecret)
    {
        MemoryStream msDecrypt = null;
        string result = null;
        try
        {
            byte[] data = Convert.FromBase64String(body);
            byte[] key = Encoding.UTF8.GetBytes(appSecret);
            msDecrypt = new MemoryStream(data);
            DESCryptoServiceProvider descCryptoServiceProvider = new DESCryptoServiceProvider();
            descCryptoServiceProvider.Mode = CipherMode.ECB;
            descCryptoServiceProvider.Padding = PaddingMode.PKCS7;
            CryptoStream cryptoStream = new CryptoStream(msDecrypt, descCryptoServiceProvider.CreateDecryptor(key, null), CryptoStreamMode.Read);
    
            byte[] buffer = new byte[data.Length];
            cryptoStream.Read(buffer, 0, (int)data.Length);
            result = Encoding.UTF8.GetString(buffer);
            return result;
        }
        catch (Exception e)
        {
            throw e;
        }
        finally {
            if (msDecrypt != null)
                msDecrypt.Dispose();
        }
    }
    
  2. sign签名方式

    为加强对外调用的接口的安全性,提供了可选的签名验证机制。参与签名的有toUser、createTime、body三个字段,按照ASCII码顺序从小到大对三个字段排序后,使用SHA1签名算法进行签名后再进行BASE64编码。
    Java示例如下:

    /**
     * toUser、createTime、body排序后再SHA1签名,Base64编码
     */
    public static String sign(String toUser, String createTime, String body) {
        String[] signArr = {toUser, createTime, body};
        Arrays.sort(signArr);
        return sha1Base64(org.apache.commons.lang.StringUtils.join(signArr));
    }
    
    public static String sha1Base64(String s) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(s.getBytes());
            return encodeBase64(md.digest());
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
    
    public static String encodeBase64(byte[] b) {
        return org.apache.commons.codec.binary.Base64.encodeBase64(b);
    }
    
    /* C# 示例 */
    public static string Sign(String toUser, String createTime, String body)
    {
        string result = null;
        try
        {
            string[] arr = { toUser, createTime, body };
            Array.Sort(arr,string.CompareOrdinal);
            string data = string.Join("", arr);
            SHA1 sha1 = SHA1.Create();
            byte[] buffer = sha1.ComputeHash(Encoding.UTF8.GetBytes(data));
            sha1.Clear();
    
            result = Convert.ToBase64String(buffer);
            return result;
        }
        catch (Exception e) {
            throw e;
        }
    }
    

2.2 内部约定登录

在可信的第三方App已有基础数据,不需要获取平台基础数据时,可以按约定通过本地学籍号或者老师家长手机号登录,此种登录方式不适于微信端。
1.服务端创建登录令牌,接口地址:

http://open.csedu.gov.cn/open/api/createLoginToken?accessToken=token&areaStudentCode=code
http://open.csedu.gov.cn/open/api/createLoginToken?accessToken=token&phone=phone

正常返回结果为{"success": true,"result": "loginToken"},其中参数accessToken来自获取accessToken结果,areaStudentCode为本地学籍号,phone为家长或老师手机号码。登录令牌的有效期为1分钟,仅能登陆一次。
当一个账号下有多个身份时, 如一个手机号码既有老师身份也有家长身份时,使用先绑定的身份做为登录后的身份。
测试环境可用数据

areaStudentCode 2222222222,1111111111
phone 13100000002(家长),13300000001(老师)

2.重定向用户页面访问下面地址完成免登录访问
http://open.csedu.gov.cn/passport/loginByToken?loginToken=token&redirectUri=uri
其中参数loginToken为步骤1返回值,redirectUri为最终访问地址(需进行url编码),如在验证中出现异常则跳到登陆页面,如果需要登录的用户和人人通系统当前已登录用户相同时,不会进行二次登录。
测试环境redirectUri可以设置为http://rate.ddu.asia 来检测登录是否成功

3 用户

3.1 根据openid获取用户关联身份

http://open.csedu.gov.cn/open/api/user/people/list?accessToken=token&userOpenId=openId

返回结构见返回值,一个正常的返回如下:

{"result":[{peopleOpenId:"", peopleType:"Teacher"}],"success":true}

result里返回的是身份*列表*,peopleType参见10.2,peopleOpenId就是所属身份的id。

4 教育局

4.1 获取所有教育局信息

http://open.csedu.gov.cn/open/api/organ/list?accessToken=token

返回结构见返回值,返回值的业务字段result类型为教育局模型 列表

4.2 教育局模型

字段 说明 是否必返回
openId 教育局id
name 教育局名称
regionName 地区名称
parentOpenId 上级教育局id
regionLevel 教育局行政级别

5 学校

5.1 获取学校信息

可以根据教育局id来查询下属学校 列表:

http://open.csedu.gov.cn/open/api/school/list?accessToken=token&eduId=eduId&studyStep=studyStep
参数 说明 是否必填
accessToken 获取accessToken
eduId 教育局模型里的openId
studyStep 学习阶段

正常返回值里的业务字段为学校模型 列表
也可以通过指定学校id来返回某一个学校的信息:

http://open.csedu.gov.cn/open/api/school?accessToken=token&schoolOpenId=openId

正常返回值里的业务字段为学校模型

5.2 学校模型

字段 说明 是否必返回
openId 学校Id
name 学校名称
studyStep 学习阶段
parentOpenId 上级教育局Id

5.3 查询数据变化状态

我们建议在关联具体身份业务时,再通过对应接口获取该角色的业务信息,但在学校范围内,可能需要获取的信息非常多,为了业务的简单及用户的体验,提供了获取学校数据变化状态的接口,应用可以定时获取已改变的学校基础信息,来保持学校信息的最终一致。

5.3.1 查询学校最后修改时间

http://open.csedu.gov.cn/open/api/school/modifyTime?accessToken=token&schoolOpenId=openId

正确返回结果

{"success":true, result:{"Student":"2018-04-09 08:54:42","Parent":"2018-04-09 08:54:42"}}

其中Result里为Key-Value对应形式,key代表改变的类型,value代表最后修改时间,为空代表服务到现在没有修改记录,key的取值范围参考10.2的编码

5.3.2 查询今天、3天内(包含今天)、60天内(包含今天)的修改学校

今天:http://open.csedu.gov.cn/open/api/school/modifiedToday?accessToken=token
3天内:http://open.csedu.gov.cn/open/api/school/modified3Day?accessToken=token
60天内:http://open.csedu.gov.cn/open/api/school/modified60Day?accessToken=token

正确返回结果{"success":true, result:["aUofj0Alw6E8Vl67aEg77A==","PPqwWWm17Io5dha6wMDexA=="]} ,返回的result里为修改学校的openId数组

6 班级

6.1 获取班级信息

可以根据学校id和入学学年来查询下属班级列表:

http://open.csedu.gov.cn/open/api/classes/list?accessToken=token&schId=schId&inYear=inYear
参数 说明 是否必填
accessToken 获取accessToken
schId 学校模型里的openId
inYear 该班级的入学学年

正常返回值里的业务字段为班级模型 列表
也可以通过指定班级id来返回某一个班级的信息:

http://open.csedu.gov.cn/open/api/classes?accessToken=token&classOpenId=openId

正常返回值里的业务字段为班级模型

6.2 班级模型

字段 说明 是否必返回
openId 班级Id
name 班级名称
inYear 班级入学学年
studyStep 学习阶段
schoolOpenId 学校Id

7 老师

7.1 获取老师信息

可以根据学校id和老师姓名来查询老师信息:

http://open.csedu.gov.cn/open/api/teacher/list?accessToken=token&schId=schId&name=name
参数 说明 是否必填
accessToken 获取accessToken
schId 学校模型里的openId
name 老师名字

正常返回值里的业务字段为老师模型 列表
也可以通过指定老师id来返回某一个老师的信息:

http://open.csedu.gov.cn/open/api/teacher?accessToken=token&classOpenId=openId

正常返回值里的业务字段为老师模型

7.2 老师模型

字段 说明 是否必返回
openId 班级Id
name 班级名称
inYear 班级入学学年
studyStep 学习阶段
schoolOpenId 学校Id

8 人人通

9 备注

9.1 示例为测试环境,正式环境会更换域名、clientId、secret

9.2 所有HTTP交互接口,如无特殊说明,字符集编码为UTF-8

10 附录

10.1 省市机构

10.2 用户身份类型

身份类型 编码
学生 Student
家长 Parent
老师 Teacher
班级 Class
学校管理员 School
教育局管理员 Organ

10.3 学习阶段

阶段 编码
小学 1
初中 2
高中 4

10.4 教育局行政级别

级别 编码
省级 2
市级 4
县级 6

10.5 家长关系

身份 编码
家长 0
爸爸 21
妈妈 22
爷爷 31
奶奶 32
外公 33
外婆 34