客户端集成与认证
客户端集成及授权其主要使命在于实现对外部第三方应用的集成,将它们连接至incloud平台。 这些第三方应用需要获取incloud平台的用户信息或者访问incloud平台提供的接口。 然而,大部分incloud平台的接口都需要经过认证和授权。因此,为了实现这一目标, 对接的客户端必须在incloud平台中进行创建和注册。
这些对接的客户端将获得一个唯一的客户端ID以及一份加密凭证, 这些信息时进行与incloud平台接口的安全通信的关键,但仅有这些信息还不足以实现对接。
此外,incloud平台还需要明确授权对应客户端的接口访问权限,以确保仅授权的客户端可以访问所需的接口。 客户端管理过程为外部应用提供了合法且安全的介入方式,以访问incloud平台的资源和功能。 这种方法也保障了数据的安全性和隐私,以满足对接客户端和incloud平台的需求。
客户端凭证维护
客户端凭证系统已经提供了维护功能,请参考【系统集成】

参数说明
客户端id
随机生成的客户端id,用于标识客户端的唯一性,由系统自动生成,不可修改。
客户端名称
用户的客户端名称,用于标识客户端的名称,由管理员自行填写。
状态
启用或禁用客户端,禁用后,客户端将无法访问incloud平台。
token过期时间
客户端认证成功后,拿到的token的有效期,支持的值有:
凭证是否加密
如果选了是,会产生客户端凭证的加密公钥,加密公钥为RSA加密。
客户端凭证加密公钥
RSA加密公钥,用于加密客户端凭证,不可修改,请注意保存。
是否验证密码
如果选了是,使用客户端获取token时,还需要传入用户信息(不管是不是验证密码,用户信息都要传 ),并需要传入密码,incloud平台会验证密码是否正确。
密码加密公钥
RSA加密公钥,用于加密用户的用户和密码信息、不可修改,请注意保存。
匿名用户
对于一些特殊的客户端,如果只是想获取token,获取后,请求平台接口时, 不需要传入具体用户(不管是不是验证密码,用户信息都要传), 可以传入一个特殊的用户——匿名用户,如:${客户端id}_anonymous, 这样就可以通过匿名用户访问系统资源。
客户端集成示例
本地创建一个工程,引入下面依赖。
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
编写Java测试代码,如下:
package com.netwisd.base.demo;
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
@Data
@Slf4j
public class Test {
//客户端ID
public static final String clientId = "1714820730252750850";
//客户端凭证
public static final String clientSecret = "kSxc3vyc*BOdf#8rMYnuvQ!3MSJgTDz8";
//客户端凭证的加密公钥
public static final String clientSecretPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK2drcAzQ7CXopAwYaNagzvdezbLrWecnXtjQNFGx9rv8IrGciSjCg/jM0gRGqoaEK6835OdRGhhAGYCLh5zraYfnXcXESijyqnr/OOqBJzFAGg09eXl1h55gLZxZ1deU+VEuvjOiiDmcC0KdVSHwPajnZeSRjw/AeMP3FrjPxNQIDAQAB";
//密码的加密公钥
public static final String pwdPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2LVbagByJN9+7ZUT8yKc611gGcprBUsIEtCGVW1y37LXTx1L18mRiGUJYMA2wNwvOomZ9W1mYe6KHre7nB36qM31U25aV452pWy5jmrWw5MBF2Np9vcbkrb8GhAS1btQp9rilbLViWv+ECMiQKPMT8kHyAzJiuwmENTUKK0jQ7wIDAQAB";
//用户名
public static final String userName = "admin";
//用户密码
public static final String userPassword = "123456";
//接口请求地址
public static final String apiUrl = "http://192.168.0.92/api/v5.0";
public static void main(String[] args) {
//获取Token
String tokenRes = getToken();
AccessToken accessToken = JSONUtil.toBean(tokenRes, AccessToken.class);
log.info("token数据为:{}", accessToken.getAccessToken());
//请求接口示例
demo1(accessToken.getAccessToken());
}
//获取Token
private static String getToken() {
//获取授权码
String result = HttpUtil.post(apiUrl + "/authCode", "");
String authCode = JSONUtil.toBean(result, Result.class).getData();
log.info("获取到到授权码为:{}", authCode);
String clientSecretData = getClientSecretByEncipher(authCode);
log.info("客户端加密后的凭证信息 : {}", clientSecretData);
String authorization = "Basic " + Base64.encode(clientId + ":" + clientSecretData);
//如客户端是否加密选择的否 直接 Basic
//String authorization = "Basic " + Base64.encode(clientId + ":" + clientSecret);
HttpResponse response = null;
Result tokenResult = new Result();
try {
HttpRequest request = HttpUtil.createPost(apiUrl + "/client/oauth");
request.header("Authorization", authorization);
request.contentType("application/x-www-form-urlencoded");
request.body("username=" + clientId + "_anonymous");
//是否验证密码 选择是 放开此行
//request.body("username=" + userName + "&password=" + getPwd(userPassword));
response = request.execute();
String resp = response.body();
if (response.isOk()) {
tokenResult = JSONUtil.toBean(resp, Result.class);
} else {
log.error("获取Token失败,错误信息:{}", resp);
}
} catch (Exception e) {
log.error("获取失败", e);
} finally {
if (response != null)
response.close();
}
return tokenResult.getData();
}
//加密处理客户端凭证
private static String getClientSecretByEncipher(String authCode) {
RSA rsa = SecureUtil.rsa(null, Test.clientSecretPublicKey);
byte[] encrypt = rsa.encrypt(authCode + Test.clientSecret, KeyType.PublicKey);
return Base64.encode(encrypt);
}
//用户密码加密
private static String getPwd(String pwd) {
RSA rsa = SecureUtil.rsa(null, Test.pwdPublicKey);
byte[] encrypt = rsa.encrypt(pwd, KeyType.PublicKey);
return Base64.encode(encrypt);
}
private static void demo1(String accessToken) {
HttpResponse response = null;
try {
HttpRequest request = HttpUtil.createGet(apiUrl + "/demo/wfExpressionUser/getUserByUserIds?userIds=xxx&deptIds=xxx");
request.header("Authorization", "Bearer " + accessToken);
response = request.execute();
log.info("请求响应状态:{}", response.getStatus());
log.info("请求响应信息:{}", response.body());
} catch (Exception e) {
log.info("调用失败:", e);
} finally {
if (response != null) {
response.close();
}
}
}
@Data
static
class Result {
private Integer code;
private String msg;
private String data;
}
@Data
static
class AccessToken {
private String accessToken;
private User loginUser;
}
@Data
static
class User {
public Long id;
@Schema(description = "组织ID")
private String orgId;
@Schema(description = "组织名称")
private String orgName;
@Schema(description = "机构ID")
private Long institutionId;
@Schema(description = "机构名称")
private String institutionName;
@Schema(description = "组织全路径ID")
private String orgFullId;
@Schema(description = "组织全路径名称")
private String orgFullName;
@Schema(description = "用户名")
private String userName;
@Schema(description = "用户Code")
private String userCode;
@Schema(description = "用户中文姓名")
private String userNameCh;
@Schema(description = "手机号")
private String phoneNum;
@Schema(description = "用户密码")
private String passWord;
@Schema(description = "身份证号")
private String idCard;
@Schema(description = "邮箱")
private String email;
@Schema(description = "adminType")
private String adminType;
@Schema(description = "用户头像-上传的文件id")
private String photoFileId;
@Schema(description = "是否二级单位管理员")
private Integer isSecondaryUnitManage;
@Schema(description = "主题")
private String theme;
@Schema(description = "业务端主题")
private String bizTheme;
@Schema(description = "扩展字段")
private Map<String, Object> otherInfo = new HashMap<>();
}
}
Last modified: 20 一月 2025