Skip to main content

用户信息

本文介绍如何定制智能表单获取登录用户信息。要点如下:

1. 定制获取登录用户信息

支持版本:v1.10.0

智能表单默认从 sino-matrix 中的 uias 服务中读取登录用户信息。如果您需要从第三方服务中读取登录用户信息,则需要在 application.yml 中定制以下接口:

url:
# 指定自定义的获取用户基本信息接口
get-user-info-by-id-url: http://localhost:8888/apis/get-user-info-by-id
# 指定自定义的获取指定用户所属的所有部门信息接口(如果是一人多部门,则返回所有的部门即可)
get-all-dept-by-user-id: http://localhost:8888/apis/get-all-dept-by-user-id
# 指定自定义的获取用户所具有的业务角色接口
get-flow-roles-by-id: http://localhost:8888/apis/get-flow-roles-by-id
# 指定自定义的获取指定部门的部门信息接口
get-dept-info-by-dept-id: http://localhost:8888/apis/get-dept-info-by-dept-id
# 指定自定义的获取指定部门所有上级部门信息接口
get-all-super-dept-by-id: http://localhost:8888/apis/get-all-super-dept-by-id
# 指定自定义的获取用户基本信息的接口(仅当集成 cas 单点登录时,需要配置并实现此接口)
get-user-info-by-name-url: http://localhost:8888/apis/get-user-info-by-name

下面分章节介绍每一个接口。

1.1. 获取用户基本信息接口

配置项

url.get-user-info-by-id-url

请求方法

GET

请求参数

  • uid - 用户 id

接口响应

需要以 application/json 格式返回以下格式的信息:

{
"status": "1",
"msg": "获取用户信息成功",
"userInfo": {
"uid": "用户编号",
"userFullName": "用户姓名",
"phone": "电话号码"
}
}

如果获取失败,可以返回以下格式的信息:

{
"status": "0",
"msg": "用户不存在"
}

1.2. 获取用户所具有的业务角色接口

配置项

url.get-flow-roles-by-id

请求方法

GET

请求参数

  • userId - 用户 id

接口响应

需要以 application/json 格式返回以下格式的信息:

{
"status": "1",
"msg": "获取用户所具有的业务角色信息成功",
"rolesInfo": [
{
"rolesId": "业务角色编号1",
"rolesName": "业务角色名称1"
},
{
"rolesId": "业务角色编号2",
"rolesName": "业务角色名称2"
}
]
}

如果获取失败,可以返回以下格式的信息:

{
"status": "0",
"msg": "用户不存在"
}

1.3. 获取用户所属部门信息接口

配置项

url.get-all-dept-by-user-id

请求方法

GET

请求参数

  • userId - 用户 id

接口响应

需要以 application/json 格式返回以下格式的信息:

{
"status": "1",
"msg": "获取用户所属部门信息成功",
"deptInfo": [
{
"deptid": "部门编号1",
"deptname": "部门名称1"
},
{
"deptid": "部门编号2",
"deptname": "部门名称2"
}
]
}
注意

请注意大小写。deptiddeptname 属性名都是小写的。

提示

对于一人多部门的情况,智能表单会认为此接口响应的第一个部门是默认部门。

如果获取失败,可以返回以下格式的信息:

{
"status": "0",
"msg": "用户不存在"
}

1.4. 获取指定部门的部门信息接口

配置项

url.get-dept-info-by-dept-id

请求方法

GET

请求参数

  • deptId - 部门 id

接口响应

需要以 application/json 格式返回以下格式的信息:

{
"status": "1",
"msg": "获取部门信息成功",
"deptInfo": [
{
"deptid": "部门编号1",
"deptname": "部门名称1"
}
]
}
注意

请注意,deptInfo 是一个对象数组。

如果获取失败,可以返回以下格式的信息:

{
"status": "0",
"msg": "部门不存在"
}

1.5. 获取指定部门的所有上级部门接口

配置项

url.get-all-super-dept-by-id

请求方法

GET

请求参数

  • deptId - 部门 id

接口响应

需要以 application/json 格式返回以下格式的信息:

{
"status": "1",
"msg": "获取上级部门信息成功",
"deptInfo": [
{
"deptid": "一级部门编号",
"deptname": "xx集团",
"treeId": "001"
},
{
"deptid": "二级部门编号",
"deptname": "xx子公司",
"treeId": "001001"
},
{
"deptid": "三级部门编号",
"deptname": "xx处室",
"treeId": "001001003"
}
]
}

1.6. 根据用户名获取用户基本信息接口

配置项

url.get-user-info-by-name-url

请求方法

GET

请求参数

  • uName - 用户名

接口响应

需要以 application/json 格式返回以下格式的信息:

{
"status": "1",
"msg": "获取用户信息成功",
"userInfo": {
"uid": "用户编号",
"userFullName": "用户姓名",
"phone": "电话号码"
}
}

如果获取失败,可以返回以下格式的信息:

{
"status": "0",
"msg": "用户不存在"
}
提示

智能表单使用此接口主要用于两个方面:

  • 表单导航资源和数据的权限判定(例如部门领导能够查询到本部门以及下属部门的表单数据)
  • 显示完整的部门信息(例如表单数据创建人所在部门信息)
关于 treeId

智能表单会根据 treeId 的位数识别部门级别,位数越少,级别越高。

可以不返回 treeId,则返回的部门数组必须是从上级到下级排序的。

如果获取失败,可以返回以下格式的信息:

{
"status": "0",
"msg": "部门不存在"
}

2. 优化接口性能

支持版本:1.12.4

智能表单后端没有维护会话状态(session),所以在需要获取当前用户信息时,都是调用接口来获取的。为了良好的性能,智能表单实现了接口响应的缓存功能。每个接口的缓存时长都是可以定制的。接口的默认缓存时长和对应的缓存时长配置项如下表所示:

接口缓存时长缓存时长配置项
get-user-info-by-id-url30 分钟sinoform.user-cache-time
get-all-dept-by-user-id30 分钟sinoform.user-cache-time
get-flow-roles-by-id5 分钟sinoform.user-roles-cache-time
get-dept-info-by-dept-id1 小时sinoform.dept-cache-time
get-all-super-dept-by-id1 小时sinoform.dept-path-cache-time
缓存时长单位

所有的缓存时长配置值的单位是 毫秒

默认的缓存时长配置如下:

sinoform:
# 用户信息缓存时长:30分钟(单位:毫秒)
user-cache-time: 1800000
# 用户对应的业务角色信息缓存时长:5分钟(单位:毫秒)
user-roles-cache-time: 300000
# 部门信息缓存时长:1小时(单位:毫秒)
dept-cache-time: 3600000
# 部门路径信息缓存时长:1小时(单位:毫秒)
dept-path-cache-time: 3600000

3. 获取登录用户信息

智能表单服务提供获取登录用户信息的接口,如下所示:

GET http://<智能表单访问地址>/apis/intellisense-form/userInfo

从请求中识别当前用户 id

通过以下两种方式识别当前用户的 id:

  • 通过请求头 sinoform-current-user-id(一般由网关提供此请求头)
  • 通过请求 cookie SSOID

方式一适合通过可编程网关(如 spring-cloud-gateway)实现多系统共享 session 的方案,在网关上将当前用户 id 放入请求头 sinoform-current-user-id 中。方式二适合使用 sinomatrix sso 实现多系统单点登录的情况。

接口响应

此接口返回的内容如下:

{
"userId": "4028d00e6f16845c016f79dda0c20231",
"userName": "张三",
"deptId": "4028d00e6ec96438016ec97b4b10000b",
"deptName": "处室一",
"roleIds": ["4028d00e7a6613f4017af154f7840454"],
"roleNames": ["处员"],
"deptInfo": [
"4028d00e6ec96438016ec97b4b10000b",
"4028d00e6ec96438016ec976fee20000",
"4028d00e6ec42073016ec4629a490001"
],
"deptInfoName": ["处室一", "分公司", "集团"],
"allDeptIds": [
"4028d00e6ec96438016ec97b4b10000b",
"2128d00e6ed1df338016ec97b4b10000b"
]
}

数据项的含义如下表所示:

属性名说明来源
userId用户 id从请求中获取
userName用户信息get-user-info-by-id-url 中的 userName 属性
deptId所属部门 id如果有请求头 sinoform-current-dept-id,则为之;否则等于 get-all-dept-by-user-id 第一条数据的 deptId
deptName所属部门名称get-dept-info-by-dept-id 中的 deptname 属性
roleIds用户拥有的业务角色 idget-flow-roles-by-id 中的 rolesId
roleNames用户拥有的业务角色名称get-flow-roles-by-id 中的 rolesName
deptInfo用户所属部门所有祖先部门 id(包含自身所属部门),即部门路径,从小到大排序,如 处室一分公司集团get-all-super-dept-by-id 中的 deptid
deptInfoName用户所属部门所有祖先部门名称(包含自身所属部门),即部门路径,从小到大排序,如 处室一分公司集团get-all-super-dept-by-id 中的 deptname
allDeptIds用户所有在职部门 idget-all-dept-by-user-id 中的 deptid

4. 由业务系统控制当前会话用户

业务系统可以通过可编程网关(如 spring cloud gateway)来告知智能表单当前会话用户(即登录用户)是谁,以及属于哪个部门(解决一人多岗的问题)。

通过网关实现登录或者与第三方 SSO 集成后,获取到当前用户的 userId 和 deptId,然后通过 sinoform-current-user-idsinoform-current-dept-id 请求头告知智能表单即可。

可以通过过滤器来实现,例如:

package com.sinosoft.sinoformgateway.filters;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
* 将会话用户信息同步到智能表单的过滤器
*/
@Component
@Slf4j
public class AuthFilter extends ZuulFilter {
private static final String USER_ID_HEAD_NAME = "sinoform-current-user-id";
private static final String DEPT_ID_HEAD_NAME = "sinoform-current-dept-id";

@Override
public String filterType() {
return PRE_TYPE;
}

@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1; //在 PreDecoration 阶段之前执行
}

@Override
public boolean shouldFilter() {
return true; // 每个请求都执行此过滤器(项目组可以根据实际情况,添加一些过滤逻辑)
}

@Override
public Object run() {
// 将登录用户的userId和deptId通过请求头的方式同步到智能表单
RequestContext ctx = RequestContext.getCurrentContext();
HttpSession httpSession = ctx.getRequest().getSession();

getUserInfoFromSession(httpSession).ifPresent(userInfo -> {
ctx.addZuulRequestHeader(USER_ID_HEAD_NAME, userInfo.getUserId());
ctx.addZuulRequestHeader(DEPT_ID_HEAD_NAME, userInfo.getDeptId());
});

return null;
}

private Optional<UserInfo> getUserInfoFromSession(HttpSession session) {
Object userInfo = session.getAttribute("user");

if (userInfo != null) {
return Optional.of((UserInfo)userInfo);
}

return Optional.empty();
}
}

之前推荐项目组直接在网关中拦截并实现 /apis/intellisense-form/common/userInfo 接口。如果采用过滤器方案,则不需要这么做,可以将网关中的此接口删除掉。

注意:本示例是从 session 中获取当前用户信息的。项目组可以根据自身的情况,可以从不同的地方获取,例如第三方 SSO。

5. 切换当前用户所属部门

如果一个用户属于多个部门,那么可以通过以下两种方式告知智能表单当前用户的所属部门,以支持一人多岗切换:

  • 方式一:通过 sinoform-current-dept-id 请求头告知智能表单(适合网关模式)
  • 方式二:通过 sinoform-current-dept-id cookie 告知智能表单(适合共同使用 sinomatrix sso 的情况,前提是:业务系统与智能表单是同域名)

第 4 章节已经说明了方式一。本章节重点讲解方式二。

最低版本要求:

  • 1.13.15
  • 1.14.1

在业务系统切换当前用户所属部门时,可以将部门信息写入到 sinoform-current-dept-id cookie 中,因为智能表单与业务系统是同域名的,所以智能表单也能接收到此 cookie。

重要提示

此方式只适合智能表单和业务系统在同一个域名下的情况。

当前用户所属部门 cookie 名称默认为 sinoform-current-dept-id,可以通过下面的配置项更改此默认名称:

application.yaml
sinoform:
dept-id-cookie-name: custom-current-dept-id

当你在集成时发现没有达到预期效果,那么需要查看一下 cookie 值是否正确。

提示

当集成遇到问题,需要平台组协助时,请截取下面两张图并发给平台组同事。

可以打开 Chrome devtools,切换到应用页签,查看 cookie 值。如下图所示:

或者切换到网络页签,找到 /userInfo 接口,从请求头中查看 cookie 值。如下图所示: