Connector 自定义源或目标¶
最后更新:2021-12-13
1. 基础约束¶
基础约束
插件工程命名 开发插件时,首先要新建一个插件的子module,插件工程的名字统一为 sync-plugin-xxxx,名称统一小写,如果名称是2个单词,建议用中线“-”分开。例如:IDP4Scim 命名为:sync-plugin-idp4-scim;
插件包依赖 新建子模块也是maven工程,该工程的父模块为:idp4-sync ;其依赖的工程只能有:sync-engine ,不建议依赖其他工程,特别不要依赖是 sync-core-local\sync-core-web\sync-application\sync-application-console
插件包命名统一为:com.idsmanager.idp.sync.plugin.xxxx ;例如IDP4的插件包命名为:com.idsmanager.idp.sync.plugin.idp4
2. 自定义来源插件¶
demo地址:https://github.com/aliyun-idaas/connector-source-demo
2.1. 工程说明¶
插件中主要分为 “数据实体、数据映射、配置文件、同步逻辑”模块。
其中各模块中重要的类有:
DemoSourceConnectionMetadata.java
数据源连接的基础方法类,同步引擎根据数据源提供的文档实现各种查询方法。
_DemoConfiguration.java _
数据源各项页面配置,页面提交的数据源配置参数会落到该类。
DemoAccountEntity.java
DemoOrganizationEntity.java
数据源账户和组织机构的字段。
DemoSourceDataPullClient.java** **
数据源拉取数据类,其中会实现数据源API文档中拉取数据的逻辑,包括增量全量逻辑。
DemoAttributeGetter.java
来源字段映射为目标字段的类。
2.2. 开发流程¶
2.2.1. 修改名称¶
将sync-plugin-demo工程中的demo,修改为具体业务名称。
必须修改模块名称,禁止使用demo字样
比如:pom中的 **artifactId **、包名、类名等
2.2.2. 修改类型名称¶
修改_DemoSourceConnectionMetadata_中的主、子类型名称,需要在对应的主子类型中添加相应的枚举,一般只允许添加子类型枚举。子类型以**_SCHEMA**结尾,前端才能获取到相应的表单json信息。
2.2.3. 修改Entity类中¶
修改DemoSourceAccountEntity, DemoSourceOrganizationEntity, DemoSourceBaseEntity类的属性为具体字段。
DemoSourceBaseEntity为抽象类,定义了一些默认参数,一般情况下可以不用管。
DemoSourceAccountEntity和DemoSourceOrganizationEntity为同步到目标所需要的实际字段,同时有一些同步必须的字段,实现了SourceDataItem的接口,需要返回什么值,详见相应方法上的**TODO**。
2.2.4. 修改默认字段映射字段¶
2.2.5. 修改来源管理页面参数字段¶
修改DemoSourceClientConfiguration和DemoConfiguration类,来定义页面上配置来源管理中所需要填写的字段。
DemoConfiguration定义来源和来源管理中,通用的字段。
DemoSourceClientConfiguration定义来源管理中,特有的字段。
修改resources下的SCHEMA模板,key与上面的字段一致,具体如何使用这个SCHEMA,会在下面进行详细说明。前端页面会获取这个json的各种信息进行渲染,前端提交参数后会转换为configuration类,在后续代码中使用。
2.2.6. 修改同步拉取数据方法¶
拉取数据源的数据操作实现都在**DemoSourceDataPullClient**。
context 数据推送上下文对象,可以获取当前正在推送的任务、来源、目标、任务批次ID等信息,也能获取当前的同步引擎核心对象的实例(DataTransformEngine) ,里边封装了很多目标插件需要的接口,具体可查看代码注释。
数据拉取的具体业务逻辑,不同插件要求各部相同,就需要插件的实现者,根据项目需求,酌情实现。这里强调一点:**无论同步哪一种对象,目标系统一定要提供一个该对象的唯一不变字段,用于我们识别同一个对象;具体有以下4个方法
pullRegularData
拉取常规的指定对象类型的数据。一次性拉取数据无序。对应“经典目录模式(无序)”
pullFullRegularOneLevelChildren
全量拉取指定的组织和用户。
同步引擎会从根一层一层调用该方法,直至数据不再有下级数据,适用于活动目录类型的数据源。(保证数据质量,不要尾首相接,导致无限循环)
拉取人员时会先一层一层先拉组织,再同时拉取组织下的人员。对应“活动目录模式(有序)”
pullFullRegularChildrenByPage:
分页模式拉取数据
pullDeletedData
拉取已删除的指定对象类型的数据。
拉取逻辑实现后最终组装成 List
3. 自定义目标插件¶
demo地址:https://github.com/aliyun-idaas/connector-target-demo
3.1. 工程说明¶
插件中主要分为 “数据实体、数据映射、配置文件、同步逻辑”模块。
其中各模块中重要的类有:
DemoTargetConnectionMetadata.java
目标系统连接的基础方法类,同步引擎根据目标系统提供的文档实现各种查询方法。
_DemoConfiguration.java _
目标系统各项页面配置,页面提交的目标系统配置参数会落到该类。
DemoTargetAccountEntity.java
DemoTargetOrganizationEntity.java
目标系统账户和组织机构的字段。
DemoTargetDataPushClient.java** **
目标系统推送数据类,其中会实现目标系统API文档中推送数据的逻辑,包括增量全量逻辑。
DemoAttributeSetter.java
把来源的属性映射为目标字段的属性。
3.2. 开发流程¶
3.2.1. 修改名称¶
将sync-plugin-demo工程中的demo,修改为具体业务名称。
必须修改模块名称,禁止使用demo字样
比如:pom中的 **artifactId **、包名、类名等
3.2.2. 修改类型名称¶
修改DemoTargetConnectionMetadata中的主、子类型名称,需要在对应的主子类型中添加相应的枚举,一般只允许添加子类型枚举。子类型以**_SCHEMA**结尾,前端才能获取到相应的表单json信息。
3.2.3. 修改Entity类中¶
修改DemoTargetAccountEntity, DemoTargetOrganizationEntity, DemoTargetBaseEntity类的属性为具体字段。
DemoTargetBaseEntity为抽象类,定义了一些默认参数,一般情况下可以不用管。
DemoTargetAccountEntity和DemoTargetOrganizationEntity为同步到目标所需要的实际字段,同时有一些同步必须的字段,实现了TargetDataItem的接口,需要返回什么值,详见相应方法上的**TODO**。
3.2.4. 修改默认字段映射字段¶
3.2.5. 修改目标管理页面参数字段¶
修改DemoTargetClientConfiguration和DemoConfiguration类,来定义页面上配置目标管理中所需要填写的字段。
DemoConfiguration定义来源和目标管理中,通用的字段。
DemoTargetClientConfiguration定义目标管理中,特有的字段。
修改resources下的SCHEMA模板,key与上面的字段一致,具体如何使用这个SCHEMA,会在下面进行详细说明。前端页面会获取这个json的各种信息进行渲染,前端提交参数后会转换为configuration类,在后续代码中使用。
3.2.6. 修改同步推送方法¶
ApiResult push(TargetDataItem item, DataTransformContext context, DataRelation relation) throws SCIMException; 该方法用于实现真正的向目标推送数据。
TargetDataItem item 里边是具体需要进行推送的数据对象的实例,已经完成字段映射。
这个对象是通过newTargetDataItem方法,由引擎模块sync-engine实例化的一个对象; 如果当前推送的是用户,那么 item 就是映射后的用户的具体信息;如果是机构,那么item 就是映射后的机构的具体信息。
context 数据推送上下文对象,可以获取当前正在推送的任务、来源、目标、任务批次ID等信息,也能获取当前的同步引擎核心对象的实例(DataTransformEngine) ,里边封装了很多目标插件需要的接口,具体可查看代码注释。
DataRelation relation 数据映射对象。很多场景下,同一个对象(例如用户),在来源和目标两个系统里的唯一标识,并不相同,IDsConnector支持维护映射关系。如果relation 对象不为空,代表系统中已经存在了映射关系。
例如同步到钉钉的时候,组织的唯一id是钉钉自己生成的,无法使用idp的外部id,又因为id中已经创建好了组织,钉钉的唯一id无法回写到idp中。那么这个组织唯一id的关联关系,就可以使用设个对象进行维护,并写入到数据库中,这样就能在做更新或删除操作时,能正确的找到钉钉的唯一id来执行相应操作。
数据推送的具体业务逻辑,不同插件要求各部相同,就需要插件的实现者,根据项目需求,酌情实现。这里强调一点:**无论同步哪一种对象,目标系统一定要提供一个该对象的唯一不变字段,用于我们识别同一个对象;
强烈建议,目标系统要提供根据该唯一标识字段,查询用户是否存在的接口,针对新增和更新操作,我们都是优先查询对象是否存在,存在则更新,不存在则新增(无论来源传递的操作是新增还是更新)。**同步任务中有个配置叫“是否开启检查模式”【 DataTransformTask类的 boolean isCheckModel() 方法】,在demo中,有使用示例。
4. 插件schema接口说明¶
自定义的来源插件和目标插件,需要填写的表单,由后端提供相应的schema来实现,存储到数据库时,也是以json串的形式进行存储。
4.1. 接口定义:¶
4.1.1. 获取源插件schema¶
4.1.1.1. 基本信息¶
Path:/api/sync/v1/connection/source/schema/{minorType}
**Method:**GET
4.1.1.2. 请求参数:¶
名称 |
类型 |
是否必须 |
说明 |
---|---|---|---|
minorType |
String |
是 |
插件名字 |
4.1.1.3. 返回数据¶
名字 |
类型 |
备注 |
---|---|---|
data |
object |
schema内容 |
message |
string |
错误信息 |
success |
boolean |
是否成功 |
code |
string |
错误码 |
4.1.1.4. 返回数据示例:¶
{
"status": 0,
"message": "操作成功",
"requestId": "FCD94521-2BBF-4345-9902-BD8C09C8E81D",
"data": {
"detailsData": [
{
"name": {
"en": "enterpriseId",
"zh": "enterpriseId"
},
"show": false,
"description": {
"en": "",
"zh": ""
},
"key": "instanceId"
},
{
"name": {
"en": "uuid",
"zh": "uuid"
},
"show": false,
"description": {
"en": "",
"zh": ""
},
"key": "applicationUuid"
},
{
"name": {
"en": "Application Logo",
"zh": "应用图标"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "logoUuid"
},
{
"name": {
"en": "Application ID",
"zh": "应用ID"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "purchaseId"
},
{
"name": {
"en": "Application Name",
"zh": "应用名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "name"
},
{
"name": {
"en": "Login URL",
"zh": "登录 URL"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "loginPageUrl"
},
{
"name": {
"en": "Form Submit URL",
"zh": "登录提交 URL"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "loginUrl"
},
{
"name": {
"en": "Username Name Attribute",
"zh": "登录名属性名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "usernameField"
},
{
"name": {
"en": "Password Name Attribute",
"zh": "登录密码属性名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "passwordField"
},
{
"name": {
"en": "Logon Button Name Attribute",
"zh": "登录按钮属性名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "submitField"
},
{
"name": {
"en": "Other Logon Information",
"zh": "登录其他信息"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "othersPageContent"
},
{
"name": {
"en": "Logon Success Page",
"zh": "登录成功跳转地址"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "loginSuccessPage"
},
{
"name": {
"en": "Application Status",
"zh": "应用状态"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "enabled",
"textFormat": "enabled"
},
{
"name": {
"en": "Account Linking Type",
"zh": "账户关联方式"
},
"show": false,
"description": {
"en": "",
"zh": ""
},
"key": "templateDto.templateName"
},
{
"name": {
"en": "Creator",
"zh": "创建人"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "creator"
},
{
"name": {
"en": "CreateTime",
"zh": "创建时间"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "createTime"
}
]
},
"success": true,
"code": "0"
}
4.1.2. 获取目标插件schema¶
4.1.2.1. 基本信息¶
Path:/api/sync/v1/connection/target/schema/{minorType}
**Method:**GET
4.1.2.2. 请求参数:¶
名称 |
类型 |
是否必须 |
说明 |
---|---|---|---|
minorType |
String |
是 |
插件名字 |
4.1.2.3. 返回数据¶
名字 |
类型 |
备注 |
---|---|---|
data |
object |
schema内容 |
message |
string |
错误信息 |
success |
boolean |
是否成功 |
code |
string |
错误码 |
4.1.2.4. 返回数据示例:¶
{
"status": 0,
"message": "操作成功",
"requestId": "FCD94521-2BBF-4345-9902-BD8C09C8E81D",
"data": {
"detailsData": [
{
"name": {
"en": "enterpriseId",
"zh": "enterpriseId"
},
"show": false,
"description": {
"en": "",
"zh": ""
},
"key": "instanceId"
},
{
"name": {
"en": "uuid",
"zh": "uuid"
},
"show": false,
"description": {
"en": "",
"zh": ""
},
"key": "applicationUuid"
},
{
"name": {
"en": "Application Logo",
"zh": "应用图标"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "logoUuid"
},
{
"name": {
"en": "Application ID",
"zh": "应用ID"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "purchaseId"
},
{
"name": {
"en": "Application Name",
"zh": "应用名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "name"
},
{
"name": {
"en": "Login URL",
"zh": "登录 URL"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "loginPageUrl"
},
{
"name": {
"en": "Form Submit URL",
"zh": "登录提交 URL"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "loginUrl"
},
{
"name": {
"en": "Username Name Attribute",
"zh": "登录名属性名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "usernameField"
},
{
"name": {
"en": "Password Name Attribute",
"zh": "登录密码属性名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "passwordField"
},
{
"name": {
"en": "Logon Button Name Attribute",
"zh": "登录按钮属性名称"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "submitField"
},
{
"name": {
"en": "Other Logon Information",
"zh": "登录其他信息"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "othersPageContent"
},
{
"name": {
"en": "Logon Success Page",
"zh": "登录成功跳转地址"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "loginSuccessPage"
},
{
"name": {
"en": "Application Status",
"zh": "应用状态"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "enabled",
"textFormat": "enabled"
},
{
"name": {
"en": "Account Linking Type",
"zh": "账户关联方式"
},
"show": false,
"description": {
"en": "",
"zh": ""
},
"key": "templateDto.templateName"
},
{
"name": {
"en": "Creator",
"zh": "创建人"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "creator"
},
{
"name": {
"en": "CreateTime",
"zh": "创建时间"
},
"show": true,
"description": {
"en": "",
"zh": ""
},
"key": "createTime"
}
]
},
"success": true,
"code": "0"
}
4.2. 后端插件文件说明:¶
在插件代码目录resources目录下,建立schema目录,按照下图所示,建立schema文件:
其中:
source_xxx.json 为源schema定义文件
target_xxx.json 为目标schema定义文件
xxx为插件ID,和MinorType类中定义的label一直,注意大小写
注意启用了shema配置的插件,插件命名必须为插件ID_SCHEMA
文件内容请参考sync-plugin-amdp项目,示例如下:
{
"form":{
"baseURL": "",
"authType": "oauth2",
"clientId": "",
"clientSecret": "",
"apiVersion":""
},
"template":{
"formData": [
{
"key": "baseURL",
"name": { "zh": "baseURL", "en": "baseURL" },
"type": "input",
"readonly": false,
"placeholder": { "zh": "请输入Basic URL", "en": "请输入Basic URL" },
"rules": { "required": true, "message": "请输入Basic URL", "trigger": "blur" },
"show": true,
"send": true
},
{
"key": "authType",
"name": { "zh": "认证方式", "en": "认证方式" },
"type": "radio",
"options": [
{ "label": "oauth2", "value": { "zh": "OAuth2", "en": "OAuth2" }, "disabled": false }
],
"placeholder": { "zh": "请输入Basic URL", "en": "请输入Basic URL" },
"rules": { "required": true, "message": "请输入Basic URL", "trigger": "blur" },
"show": true,
"send": true
},
{
"key": "clientId",
"name": { "zh": "Client ID", "en": "Client ID" },
"type": "input",
"readonly": false,
"placeholder": { "zh": "请输入Client ID", "en": "请输入Client ID" },
"rules": { "required": true, "message": "请输入Client ID", "trigger": "blur" },
"show": true,
"send": true
},
{
"key": "clientSecret",
"name": { "zh": "Client Secret", "en": "Client Secret" },
"type": "input",
"readonly": false,
"placeholder": { "zh": "请输入Client Secret", "en": "请输入Client Secret" },
"rules": { "required": true, "message": "请输入Client Secret", "trigger": "blur" },
"show": true,
"send": true
},
{
"key": "apiVersion",
"name": { "zh": "版本号", "en": "版本号" },
"type": "input",
"readonly": false,
"placeholder": { "zh": "请输入IDP4版本号", "en": "请输入IDP4版本号" },
"rules": { "required": true, "message": "请输入IDP4版本号", "trigger": "blur" },
"show": true,
"send": true
}
]
}
}