集成外部服务
集成外部服务时,按以下步骤进行集成:
第一步:创建集成用户,下发集成用户名、密码和平台地址
平台管理员在平台中创建用户,并给用户分配集成角色。可以所有外部系统共用同一个集成用户,也可以每个外部系统创建一个集成用户。
平台管理员线下将集成用户名、密码和平台地址下发给外部系统维护人员。
第二步:注册外部系统
平台管理员通过服务注册功能,将外部系统注册到平台中。
第三步:平台管理人员维护组织,组织自动同步到外部系统
平台管理员通过组织管理功能修改组织,平台提供两种方式进行组织同步:自动同步(定时)和手工同步(组织管理功能中提供“同步组织”功能)。
第四步:外部系统实现相关接口,在合适的时机调用平台接口
外部系统调用平台接口时,需要使用平台管理人员提供的集成用户名和密码登录后再调用平台接口。
平台与外部系统调用安全性机制:
平台调用外部系统的安全性:通过外部系统提供的apisecret来实现;外部系统调用平台的安全性:通过集成用户登录的方式来实现。
一、服务注册
服务注册时,需要提交以下参数:
中文名称:服务中文名;
接入地址:此接入地址下需要支持接口,接收通知(/notice)和服务元信息(/serviceMetaInfo)
外部服务apisecret:平台服务调用外部服务时,会带apisecret参数,外部服务通过apisecret保证调用的安全性。
二、单点登录
登录 通过门户登录后,在门户菜单中,可以看到注册的外部服务。打开外部服务时,将以浏览器页的方式打开另一个窗口,同时在地址上添加一个参数“token”。
获取用户信息 外部服务通过获取用户信息接口获取当前登录用户的详细信息,接口参考附录。
验证token 外部服务通过验证token接口判断当前是否登录,外部服务需要在自己的后台调用验证token接口,从而保证用户注销后外部服务也不能访问。
注销 用户注销后, 登录产生的token将失效。
三、组织同步
- 数据表结构
组织镜像(misc_orgsnapshot)
字段名 | 类型 | 说明 |
---|---|---|
id | varchar2(36) | 主键 |
createtime | datetime | 创建时间 |
content | clob | 组织镜像 |
digest | varchar2(256) | 组织镜像的md5 |
附录
一、平台服务接口
- 服务注册(当前仅在平台内部使用)
说明:此接口调用前必须登录集成用户
url: $platformUrl/entry/ manager/services
method: post
request cookie:
user_session: $user_session //集成用户登录后获取的user_session
request body(application/json)
{
"type": "external", //服务类型,取值范围:外部服务("external"),内部服务("")
"label": "", //服务名称
"address": "", //服务接入地址,
"apisecret": "" //外部服务apisecret,平台调用外部服务时将会使用
}
response status: 200表示成功,其它失败
- 登录
说明:此接口调用前不需要登录集成用户
url: $platformUrl/login
method: post
request body(form)
username: "" //集成用户名
password: "" //集成用户密码
response cookie
user_session: "" //后续调用平台接口时需要使用
response status: 200成功,其它失败
注意:登录时,password可以使用token替换,token的生成获取方式:
第一步,使用集成用户在浏览器中登录门户;
第二步,浏览器中输入$platformUrl//uaa/userinfo?type=token, 返回的类似如下:
{"token":"system@xDuJbx8dYfYBXu6%2B6Knke1YalZvAmvlWPm9uHuFVnkh1nQyYA6A4LcDSUI8Qk4dN","name":""}
- 注销
说明:此接口调用前不需要登录集成用户
url: $platformUrl/logout
method: get
request cookie:
user_session: "" //登录得到的user_session
response status: 200成功,其它失败
- 获取用户信息
说明:此接口调用前不需要登录集成用户
url: $platformUrl/entry/uaa/userinfo
method: get
request cookie:
user_session: $token //平台打开外部系统时给的token
response body(application/json)
{
"user_ id":"", //用户标识
" user_name ":"", //登录名
"email":"",
"phone_number":"",
" give_name ":"" //中文名
}
response status: 200成功,其它失败
- 验证token
使用"获取用户信息"模拟,如果能获取到用户信息,表示token有效,否则无效。
- 获取组织增量
说明:此接口调用前必须登录集成用户
url: $platformUrl/entry/misc/org/ getOrgSnapshot? orgDigest=$orgDigest
method: get
request cookie:
user_session: $user_session //集成用户登录获取获取的user_session
request field:
orgDigest: 外部服务当前组织镜像的md5; 当orgDigest为空或给定的orgDigest不存在时,将会返回组织最新的全量数据
response body(application/json)
{
"success": true, //状态, 取值范围true, false
"msg": "", //错误消息
"type": "delta" , //数据格式, 取值范围: 增量(delta), 全量(all),
" orgDigest ": "", //当前组织镜像的md5
"data":{
//增量数据修改时,添加一个state表示修改状态,取值范围:new,update,delete, //全量时没有state
"users": [{
//参考数据结构中的“用户”
state: "new"
}],
"orgs": [{
//参考数据结构中的“组织”
state: "new"
}]
}
}
response status: 200表示成功,其它表示失败
- 导入组织
说明:此接口调用前必须登录集成用户 uaa提供一个api:postOrgs,实现组织和人员的增删改
- URL
$platformUrl/entry/uaa/org/postOrgs
- 请求方式
POST
- 参数
{
"orgFNameSeparator": "/", //全路径名称分隔符,默认为/,可在参数配置中配置
"data": {
"type": "delta", //取值范围: 增量(delta), 全量(all)
"users": [ //用户信息
{
"state": "upsert", //当type=delta时生效, delete/upsert
"id": "", //主键
"orgs":[ "",""], //所属组织的id列表,和addOrgs/deleteOrgs不能同时出现
"addOrgs": [], //增加的组织id列表
"deleteOrgs": [], //删除的组织id列表
"mainOrg": "", //主组织的id
"created": null, //创建时间
"username": "", //登录用户名
"name": "", //用户中文名称
"verified": 1, //账号状态
"active": 1, //用户状态
"email": "", //email
"phoneNumber": "", //手机号
"address":"", //办公地址
"position": "", //职位
"description": "", //备注
"hiredate": "2021-07-21 00:00:00", //入职时间
"roles": ["", ""], //人员的角色id列表
"addRoles": ["", ""], //人员新增加的角色id列表
"deleteRoles": ["", ""], //删除的人员角色id列表
"orgRoles":[{"orgid": ["roleid"]}], //人员成员的角色id列表
"addOrgRoles": [{"orgid": ["roleid"]}], //人员成员新增加的角色id列表
"deleteOrgRoles": [{"orgid": ["roleid"]}], //删除的人员成员角色id列表
"sortNumber": 1, //排序号
"type": "org", //org代表组织内人员,sys代表system,外部人员无需设置
"manageOrgs": [{ //人员或人员成员的管理组织信息
"role": "roleid", //角色id,主管的角色id是director
"org"; "orgid", //管理者是人员时设置为空,管理者是人员成员时设置为父节点的id
"managedOrg": "orgid" //被管理组织的id
}],
"addManageOrgs": [], //内容同manageOrgs,表示新增加的管理组织信息
"deleteManageOrgs": [], //内容同manageOrgs,表示要删除的管理组织信息
"extend": {} //扩展表中的字段
}
],
"orgs": [
{
"state": "upsert", //当type=delta时生效, delete/upsert
"id": "", //组织id
"parentID": null, //父组织id
"name": "", //组织名称
"code": "", //组织编码
"type": "", //组织类型:部门(dpt),机构(ogn),岗位(pos)
"active": 1, //状态
"seq": 1, //序号
"roles": ["", ""], //拥有的角色id列表;
"addRoles": ["", ""], //新增加的角色id列表
"deleteRoles": ["", ""],//删除的角色id列表
"manageOrgs": [{ //组织的管理组织信息
"role": "roleid", //角色id,主管的角色id是director
"managedOrg": "orgid" //被管理组织的id
}],
"addManageOrgs": [], //内容同manageOrgs,表示新增加的管理组织信息
"deleteManageOrgs": [], //内容同manageOrgs,表示要删除的管理组织信息
"extend": {} //扩展表中的字段
}
]
}
}
注意事项:组织id和人员id必须唯一,不能出现组织id和人员id相同的情况
- 导入组织图片
说明:此接口调用前必须登录集成用户
url: $platformUrl/entry/misc/org/ importOrgImg
method: post
request cookie:
user_session: $user_session //集成用户登录获取获取的user_session
request body(multipart/form-data)
file: zip格式的压缩文件
response body(application/json)
{
"success": true, //状态, 取值范围true, false
"msg": "" //错误消息
}
response status: 200表示成功,其它表示失败
说明:
a. 压缩文件格式:zip格式
b. 压缩文件示例:
xx.zip
users(表名作目录名)
config.json(配置文件)
signature(字段名作目录名)
system.jpg
dev1.jpgn
config.json内容: {"lookupColumnName": "username"}
以上压缩包的含义是:更新users表中的signature字段,使用users表中的username字段作为查找条件,生成的sql类似:
update users set signature=${图片上传后生成的地址} where username=${不带后缀的图片名}
除此之外,在config.json中还可以加lookupColumnValue指定一个查询的sql, 这个sql必须返回一个字段,有且只有一个?参数,生成的语句类似:
update users set signature=${图片上传后生成的地址} where username in (${lookupColumnValue使用不带后缀的图片名替换其中的?})
c. 代码调用案例:
String path = System.getProperty("user.dir") + "/test/res.zip";
OkHttpClient client = new OkHttpClient();
File file = new File(path);
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
RequestBody body = new MultipartBuilder().type(MultipartBuilder.FORM)
.addFormDataPart("file", file.getName(), fileBody)
.build();
String url = "/xxxx/entry/misc/org/importOrgImg";
Request request = new Request.Builder().url(url).post(body).build();
Call call = client.newCall(request);
Response response = call.execute();
- 批量调用action接口
例如: 添加任务
X-batch-token: 用token替换user和password
curl -H "Content-Type: application/json" -H "X-batch-user: {用户名}" -H "X-batch-password: {密码}" -X POST https://{domain}/integration/batch -d @testwf.json
testwf.json结构
[
{
"id": "{任意id}",
"method": "POST",
"url": "https://{域名}/wf/BusinessServer/business-action",
"header": {},
"data": {
"process": "/SA/task/taskCenter/taskCenterProcess",
"activity": "mainActivity",
"action": "createCommonTaskAction",
"parameters": {
"name": "任务名称",
"process": "/SA/task/taskCenter/taskCenterProcess",
"activity": "mainActivity",
"sCURL": "$UI/SA/task/taskCenter/mainActivity.w",
"sEURL": "$UI/SA/task/taskCenter/mainActivity.w",
"sData1": "业务数据主键",
"executors": [
"用户id"
],
"options": {}
}
}
}
]
二、外部服务接口
- 接收通知
url: $接入地址/notice?apisecret=$apisecret
method: post
request field:
apisecret: $apisecret //注册外部系统时提供的apisecret
request body(application/json):
{
"type": "", //通知类型, 取值范围: "orgChanged"
"data": {} //通知数据
}
1.1 组织变化通知
{
"type": "orgChanged",
"data": {
"orgDigest": "" //最新组织镜像的md5
}
}
response status: 200表示成功,其它表示失败
- 服务信息
url: $接入地址/serviceMetaInfo? apisecret=$apisecret
method: get
request field:
apisecret: $apisecret //注册外部系统时提供的apisecret
response body(application/json)
参考数据结构中的"服务元信息"
response status: 200表示成功,其它表示失败
三、 数据结构
- 人员 (users)
参考《中台服务-企业门户-组织管理-组织相关表结构》中的用户表
- 组织 (orgs)
参考《中台服务-企业门户-组织管理-组织相关表结构》中的组织表
- 服务元信息
"serviceInfo": {
"name":"servicemanager",
"label":"微服务管理系统"
},
"menu" : {
"title":"微服务管理系统",
"children":[{
"types":["pc",”mobile”,"func",”openPage”],
"color":"#3494F8",
"icon":"dataControldataControl-c",
"title" : "服务管理",
"url" : "http://servicemanager/x5/UI2/main/fuwu_sj.w"
},{
"ext" : {
"code" : "wf_finishNotice",
"more" : {
"title" : "任务中心",
"url" : "/wf/x5/UI2/main/taskCenter.w?parameter=finished"
}
},
"types" : [ "widget", "pc" ],
"color" : "#3494F8",
"icon" : "dataControl dataControl-c",
"title" : "我的已阅",
"url" : "/entry/mobileapp/mobile/taskWidget/finishNotice.w"
},{
"title": "信息发布",
"icon": "dataControl dataControl-c",
"color": "#3494F8",
"types": [
"pc",
"mobile",
"func",
"tab"
],
"url": "/entry/mobileapp/mobile/infoPublish/infoPub.w?type=tab&$pparams=tab",
"ext": {
"tabBar": {
"iconPath": "./images/work1.png",
"selectedIconPath": "./images/work2.png"
}
}
}
]
},
"authorize" : {
"permissions" : [{
"id":"sm_permission_001",
"code" : "*:http://servicemanager/x5/UI2/main/fuwu_sj.w:get",
"name" : "服务管理",
"type" : "menu"
}, {
"code" : "*:/entry/misc/org/importOrg:post",
"name" : "导入组织",
"id" : "misc_importOrg",
"type" : "service"
}],
"roles" : [{
"id":"admin",
"code" : "admin",
"name" : "管理员",
"permissions" : [ "*:http://servicemanager/x5/UI2/main/fuwu_sj.w:get"]
}]
}
}
serviceMetaInfo包括3个节点:serviceInfo、menu和authorize。
serviceInfo节点描述应用的基本信息 name用于应用注册,需保证唯一,不能是中文的。
menu节点用来描述应用的菜单信息
menu里的第一级title定义一级菜单名称,通过children定义二级菜单或一级菜单中的菜单项。
(1)types设置菜单项的类型有(pc、pcx、mobile、func、widget、process、openPage、iframe、tab),可由下面的选项组合而成:
* pc、pcx和func代表是桌面端菜单,在桌面门户中可见,如果是流程的功能需要加上process * mobile和func代表是移动端菜单,在移动门户中可见,如果是流程的功能需要加上process,如果是移动门户导航栏需要加上tab * pc、pcx和widget代表桌面端门户首页内容块 * openPage代表会通过window.open打开对应url,url中会添加token参数 * iframe代表会在门户的功能区域,通过iframe打开 注意:如果一个功能桌面和移动端都有types中把代码移动和桌面的都配置上,不是定义两个menu 如果是要显示到菜单上的func这个类型必须配置
(2)color:移动端门户菜单图标颜色
(3)icon:门户菜单图标
(4)title:菜单名
(5)url:菜单url
* 内部页面格式为:/微服务名/mobileapp/mobile/XXX(页面有分组XXX是:分组目录/文件名,没有分组是:文件名),文件名是带.w后缀的 * 外部页面格式为:从http或者https开始的完整路径 如果types中配置了tab,url上需要加上参数type=tab&$pparams=tab,如:/entry/mobileapp/mobile/infoPublish/infoPub.w?type=tab&$pparams=tab 如果在url上要加参数需要通过$$params添加,多个参数可以用,隔开,如:/entry/mobileapp/mobile/infoPublish/infoPub.w?$pparams=apptype,market&apptype=2&market=170
(6)ext:定义扩展信息
* 如要添加tabBar图标 ,属性内容描述参考小程序tabBar格式,例如 `{"tabBar":{"iconPath":"/xxx/a.png"}}` * 如要设置widget的更多按钮打开的功能如下:
```
{ "code" : "wf_finishNotice", "more" : { "title" : "任务中心", "url" : "/wf/x5/UI2/main/taskCenter.w?parameter=finished" }
```
authorize节点用来描述应用的权限信息
permissions部分用来描述应用的所有权限列表
id:权限项id,自己定义 code:菜单项的权限中间为权限的url信息,对应菜单项中url的值;API的权限中间为API的请求路径。前面都是*:开头的,后面就是:请求类型,如get、post 当url中有$$params添加参数时,code中不需要按url中的格式写,code可以直接写即把$pparams的设置去掉,如: /entry/mobileapp/mobile/infoPublish/infoPub.w?apptype=2&market=170 code中也可以不加参数,不加参数的权限一个权限项控制了不同的参数的url的权限 name:权限项名称 type:菜单为menu,API为service,sql为数据权限。type的值是可以自己定义的,主要就是前面的code项要描述正确
roles部分是当前应用的角色列表
id:角色id code:角色code name:角色名 permissions是当前角色的权限集合
说明:
一个菜单项对应一个权限,
后台api同样可以在权限中描述,后台api描述的时候如果是同域可以进行鉴权
如果权限中有需要根据url参数区分权限项的情况,请求的时候或者描述菜单项url的时候添加参数 $pparms 来声明是权限参数。比如
http://console.newdao.net/order?type=user 这样一个请求的url,鉴权的时候会看是否有 /order的api权限.
http://console.newdao.net/order?type=user&$pparams=type 这样一个请求的url,鉴权的时候会看是否有 /order?type=user的api权限.
需要注意的是权限中定义的时候不需要添加$pparams的定义
在定义角色时,可以使用系统内置的角色。系统内置3个角色如下:
- authc是注册账户角色,用户登录后都可以访问这个角色的权限
- anonymous是匿名用户角色,用户未登录时可以访问这个角色的权限
- admin是系统管理员角色,拥有全部权限