大部分情况下,开发者集成腾讯会议SDK会选择会前会后页面使用API自定义实现,会中使用SDK自带页面的方式接入自己的APP。因此一个典型的腾讯会议SDK项目开发对接工作主要由通讯录对接(后台开发)、登录鉴权信息生成(后台开发)、SDK接入(客户端开发)、Rest API接入(后台开发)和Webhook接入(后台开发)几部分组成。本文将讲解如何进行通讯录对接开发,也就是IDaaS API接入。
IDaaS API官网文档:IDaaS开放平台通讯录API列表
在接入IDaaS API之前开发者需要了解以下信息:
1、 所有请求都是采用Bearer Token的鉴权方式
2、 请求返回成功的错误码并不都是200,具体要看每个接口的描述部分
3、 创建用户时需要有部门字段,如果不同步组织架构到腾讯会议,需要将用户都挂在默认的root部门下
4、 如果需要同步海外用户的手机号,需要和腾讯技术人员确认areaCode字段已经配置好
本文实现获取人员列表/创建人员/删除人员三个接口,将整体实现分为以下几个模块
1、 http请求实现:实现http请求的GET、POST和DELETE方法
2、 签名实现:对所有请求进行签名
3、 用户信息类:用于封装创建人员请求的body信息
4、 接口封装:提供获取人员列表/创建人员/删除人员三个接口
5、 对接信息配置:设置IDaaS API对接信息
具体实现如下(代码仅供参考)
1、 http请求实现
1.1 GET请求
代码语言:javascript复制 public static String doGet(String httpUrl, String auth, int okCode) {
HttpURLConnection conn = null;
InputStream inputStream = null;
BufferedReader bufferedReader = null;
String result = null;
try {
URL url = new URL(httpUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// 设置连接主机服务器的超时时间:15秒
conn.setConnectTimeout(15000);
// 设置读取远程返回的数据时间:60秒
conn.setReadTimeout(60000);
conn.setRequestProperty("Authorization", "Bearer " auth);
conn.connect();
if (conn.getResponseCode() == okCode) {
inputStream = conn.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, UTF_8));
StringBuilder stringBuilder = new StringBuilder();
String tmp;
while ((tmp = bufferedReader.readLine()) != null) {
stringBuilder.append(tmp);
stringBuilder.append("rn");
}
result = stringBuilder.toString();
} else {
System.out.println("error:" conn.getResponseCode());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != bufferedReader) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != conn) {
conn.disconnect();
}
}
return result;
}
1.2 POST请求
代码语言:javascript复制 public static String doPost(String httpUrl, String auth, int okCode, String param) {
HttpURLConnection conn = null;
InputStream inputStream = null;
OutputStream outputStream = null;
BufferedReader bufferedReader = null;
String result = null;
try {
URL url = new URL(httpUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
// 设置连接主机服务器超时时间:15秒
conn.setConnectTimeout(15000);
// 设置读取主机服务器返回数据超时时间:60秒
conn.setReadTimeout(60000);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "Bearer " auth);
outputStream = conn.getOutputStream();
outputStream.write(param.getBytes());
if (conn.getResponseCode() == okCode) {
inputStream = conn.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, UTF_8));
StringBuilder stringBuilder = new StringBuilder();
String tmp;
while ((tmp = bufferedReader.readLine()) != null) {
stringBuilder.append(tmp);
stringBuilder.append("rn");
}
result = stringBuilder.toString();
} else {
System.out.println("error:" conn.getResponseCode());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != bufferedReader) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != outputStream) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != conn) {
conn.disconnect();
}
}
return result;
}
1.3 DELETE请求
代码语言:javascript复制 public static String doDelete(String httpUrl, String auth, int okCode) {
HttpURLConnection conn = null;
InputStream inputStream = null;
BufferedReader bufferedReader = null;
String result = null;
try {
URL url = new URL(httpUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("DELETE");
// 设置连接主机服务器的超时时间:15秒
conn.setConnectTimeout(15000);
// 设置读取远程返回的数据时间:60秒
conn.setReadTimeout(60000);
conn.setRequestProperty("Authorization", "Bearer " auth);
conn.connect();
if (conn.getResponseCode() == okCode) {
inputStream = conn.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, UTF_8));
StringBuilder stringBuilder = new StringBuilder();
String tmp;
while ((tmp = bufferedReader.readLine()) != null) {
stringBuilder.append(tmp);
stringBuilder.append("rn");
}
result = stringBuilder.toString();
} else {
System.out.println("error:" conn.getResponseCode());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != bufferedReader) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != conn) {
conn.disconnect();
}
}
return result;
}
2、 签名实现
代码语言:javascript复制public class SignUtil {
public static String generateJWT(String kid, String serviceAccount) {
try {
//注意:这里获取到的时间戳需要是东8区的当前时间。
long now = System.currentTimeMillis();
JSONObject jwkJsonObj = JSON.parseObject(serviceAccount);
String clientId = jwkJsonObj.getString("clientId");
RSAPrivateKey privateKey = getPrivateKey(jwkJsonObj.getString("privateKey"));
if (null == privateKey) {
return null;
}
JWTClaimsSet.Builder claimsBuilder = new JWTClaimsSet.Builder()
.audience("contacts")
.expirationTime(new Date(now 600000)) //Token的过期时间,此处为10分钟。
.issueTime(new Date(now))
.issuer(clientId)
.claim("account_type","serviceAccount");
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.parse("RS256"))
.keyID(kid)
.type(JOSEObjectType.JWT)
.build();
SignedJWT signedJWT = new SignedJWT(header, claimsBuilder.build());
signedJWT.sign(new RSASSASigner(privateKey));
return signedJWT.serialize();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static RSAPrivateKey getPrivateKey(String privateKey) throws Exception {
Object privateKeyObj = new JSONParser(JSONParser.USE_HI_PRECISION_FLOAT | JSONParser.ACCEPT_TAILLING_SPACE).parse(privateKey);
if (privateKeyObj instanceof com.nimbusds.jose.shaded.json.JSONObject) {
com.nimbusds.jose.shaded.json.JSONObject jwtObject = (com.nimbusds.jose.shaded.json.JSONObject) privateKeyObj;
// Find the RSA signing key
if (jwtObject.get("use").equals("sig") && jwtObject.get("kty").equals("RSA")) {
return RSAKey.parse(jwtObject).toRSAPrivateKey();
}
}
return null;
}
}
3、 用户信息类
3.1 UserInfo.java
代码语言:javascript复制public class UserInfo {
@Expose
@SerializedName("username")
String username;
@Expose
@SerializedName("displayName")
String displayName;
@Expose
@SerializedName("primaryMail")
String primaryMail;
@Expose
@SerializedName("secondaryMail")
String secondaryMail;
@Expose
@SerializedName("deptId")
String deptId;
@Expose
@SerializedName("phoneNum")
String phoneNum;
@Expose
@SerializedName("employeeNumber")
String employeeNumber;
public void setUsername(String username) {
this.username = username;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public void setPrimaryMail(String primaryMail) {
this.primaryMail = primaryMail;
}
public void setSecondaryMail(String secondaryMail) {
this.secondaryMail = secondaryMail;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public void setEmployeeNumber(String employeeNumber) {
this.employeeNumber = employeeNumber;
}
}
3.2 CreateUserRequest.java
代码语言:javascript复制public class CreateUserRequest {
@Expose
@SerializedName("values")
UserInfo values;
public CreateUserRequest() {
values = new UserInfo();
}
public void setUsername(String username) {
this.values.username = username;
}
public void setDisplayName(String displayName) {
this.values.displayName = displayName;
}
public void setPrimaryMail(String primaryMail) {
this.values.primaryMail = primaryMail;
}
public void setSecondaryMail(String secondaryMail) {
this.values.secondaryMail = secondaryMail;
}
public void setDeptId(String deptId) {
this.values.deptId = deptId;
}
public void setPhoneNum(String phoneNum) {
this.values.phoneNum = phoneNum;
}
public void setEmployeeNumber(String employeeNumber) {
this.values.employeeNumber = employeeNumber;
}
}
4、 接口封装
代码语言:javascript复制public class IdaasApi {
public static void main(String[] args) {
String result;
//获取人员列表
result = getUserList();
System.out.println(result);
//创建人员
CreateUserRequest user = new CreateUserRequest();
user.setUsername("");
user.setDisplayName("");
user.setPrimaryMail("");
user.setDeptId("");
result = createUser(user);
System.out.println(result);
//删除人员
result = deleteUser("");
System.out.println(result);
}
public static String getUserList() {
String jwtToken = generateJWT(IdaasApiConfig.kid, IdaasApiConfig.serviceAccount);
String result;
//获取人员列表
result = HttpClient.doGet(IdaasApiConfig.httpUrl "/api/v1/users", jwtToken, 200);
return result;
}
public static String deleteUser(String userId) {
String jwtToken = generateJWT(IdaasApiConfig.kid, IdaasApiConfig.serviceAccount);
String result = HttpClient.doDelete(IdaasApiConfig.httpUrl "/api/v1/users/" userId, jwtToken, 204);
return result;
}
public static String createUser(CreateUserRequest request) {
String jwtToken = generateJWT(IdaasApiConfig.kid, IdaasApiConfig.serviceAccount);
String body = JSON.toJSONString(request);
//System.out.println(body);
String result = HttpClient.doPost(IdaasApiConfig.httpUrl "/api/v1/users", jwtToken, 201, body);
return result;
}
}
5、 对接信息配置
代码语言:javascript复制public class IdaasApiConfig {
public static final String httpUrl = "https://test-admin.id.meeting.qq.com/contacts";
//获取kid方式:ServiceAccount中的privateKey的kid
public static final String kid = "";
public static final String serviceAccount = "";
}