将外部应用部署到租户内
外部应用可以部署到租户内运行
- 外部应用提供 /serviceMetaInfo 接口,用于注册到企业门户中
- 从企业门户中调用外部应用服务时,请求头的 Cookie 中包括 user_session,可用于获取当前用户
- 外部应用调用企业门户的 /uaa/userinfo 接口,请求头的 Cookie 中包括 user_session,可获取当前用户信息,实现外部应用的登录
- 外部应用提供 /notice 接口,用于接收组织变化通知,实现组织同步
- 外部应用调用企业门户的 /misc/org/getOrgSnapshot 接口,用于获取组织数据,实现组织同步
- 外部应用通过内部域名访问企业门户的接口,一般情况(userinfo 除外)不需要 user_session,可直接访问
特别说明
- 流水线不处理数据库,建议在应用代码中,通过上下文获取数据库连接后,实现初始化
- 前后端分离的应用,需要发布为两个应用
外部应用注册
在企业门户中注册外部应用时,调用外部应用的 /serviceMetaInfo 接口,返回服务元信息,示例代码如下,其中定义了两个菜单。服务元信息详细格式参考《服务元信息》中的结构说明
{
"authorize":{
"permissions":[],
"roles":[]
},
"menu":{
"children":[
{
"children":[],
"ext":{},
"title":"demo主页",
"types":["func","pcx","openPage"],
"url":"/demo/index.html"
},
{
"children":[],
"ext":{},
"title":"demo测试页",
"types":["func","pcx","openPage"],
"url":"/demo/userinfo"
}
],
"ext":{},
"title":"demo",
"types":[]
},
"profile": "ext",
"serviceInfo":{
"label":"demo",
"name":"demo"
}
}
java 代码示例如下
@GetMapping("/serviceMetaInfo")
public Object serviceMetaInfo() throws Exception{
InputStream is = null;
try {
is = DemoController.class.getResourceAsStream("/data/meta.json");
return IOUtils.toString(is, "UTF-8");
} finally {
if (is != null) {
IOUtils.closeQuietly(is);
}
}
}
如需使用企业门户的应用资源管理,在运行时配置菜单和角色
需要调用门户的 externalServiceMetaInfo 接口,java 示例代码如下
@GetMapping("/serviceMetaInfo")
public Object serviceMetaInfo(@RequestParam(required = false, defaultValue = "false") String nosmi) throws Exception{
if(nosmi.equals("true")){
return serviceMetaInfo2();
}else{
String address = URLEncoder.encode(getOwnerDomain() + "/original", StandardCharsets.UTF_8);
String url = getEntryDomain() + "/servicemetainfoext/externalServiceMetaInfo?name=demo&label=demo&address=" + address;
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return response;
}
}
@GetMapping("/original/serviceMetaInfo")
public Object serviceMetaInfo2() throws Exception{
InputStream is = null;
try {
is = DemoController.class.getResourceAsStream("/data/meta.json");
return IOUtils.toString(is, "UTF-8");
} finally {
if (is != null) {
IOUtils.closeQuietly(is);
}
}
}
外部应用获取门户当前用户
从门户的功能树调用外部应用的服务时,Cookie 中携带 user_session。外部应用调用门户的 /uaa/userinfo 获取当前用户,该请求需要 Cookie 中携带 user_session,java 示例代码如下
@GetMapping("/userinfo")
public ResponseEntity<String> userinfo(@CookieValue("user_session") String user_session) {
String domain = getEntryDomain();
String url = domain + "/uaa/userinfo";
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie", "user_session=" + user_session);
HttpEntity<String> request2 = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
request2,
String.class
);
return response;
}
外部应用组织同步
在门户的组织同步配置中,添加外部应用,如下图所示
在门户的组织管理中,点击同步组织按钮,系统调用外部应用(需在组织同步配置中配置)的 /notice 接口,发送组织变更通知
外部系统提供 notice 接口,调用企业门户的 /misc/org/getOrgSnapshot 接口获取组织数据,java 示例代码如下
@PostMapping("/notice")
public void notice(HttpServletRequest request,@RequestBody String params) {
System.out.println(params);
String domain = getEntryDomain();
String url = domain + "/misc/org/getOrgSnapshot";
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
System.out.println(response.getBody());
}
日志输出如下图所示
更详细的示例代码参考《组织同步》中平台同步到第三方的实现接口
获取租户编码
租户内应用之间调用 API,一律使用应用内部域名。租户内应用内部域名的命名方式为:应用名.newdao-tenant-租户编码
- 租户编码:通过环境变量 TENANT_CODE 获取
- 企业门户内部域名:entry.newdao-tenant-租户编码
@Value("${TENANT_CODE}")
private String TENANT_CODE;
private String getEntryDomain(){
return "http://entry.newdao-tenant-"+ TENANT_CODE;
}
private String getOwnerDomain(){
return "http://demo.newdao-tenant-"+ TENANT_CODE;
}
使用流水线管理发布外部应用
在租户内,租户管理员通过流水线管理,可将外部应用发布到租户内或应用市场,流水线管理详细说明参考《流水线快速入门》和《流水线技术架构、接口和运行原理》
新增流水线
租户管理员登录控制台,打开“流水线管理→流水线管理”,新增流水线,流水线模版选择“外部应用部署模版”
流水线编辑
在列表中,点击流水线名称,如下图所示,进入流水线编辑
代码拉取
- 基础镜像:选择镜像类型和版本
- 代码来源:选择源码仓库或上传可执行包
构建编译
应用配置
自定义 ServiceMetaInfo 选择“是”,如下图所示
发布部署
- 内部市场:发布到应用市场
- 内部 k8s 集群:发布到当前租户
环境变量设定
在环境变量设定中,添加外部应用中的环境变量
部署后,在应用/服务管理,该应用的配置中,设置环境变量的值,如下图所示