直接跳到内容

用户组织对接

AgileBPM 提供了灵活的用户组织,面向上层的调用通过接口而不关注具体实现细节。依托 Spring 框架运行时自动注入,可对底层的实现更换而不影响上层调用。面向企业已有的鉴权和用户体系,AgileBPM 提供了两种对接方案。

接口定义

枚举

com.dstz.org.api.enums.GroupType

组类型

  • ORG:组织
  • ROLE:角色
  • POST:岗位

接口

com.dstz.org.api.UserApi

用户接口,用于获取用户相关信息

  • IUser getByUserId(String userId) (可选)
    根据用户 ID 获取用户信息,默认内部调用getByUserIds实现

  • Iterator<? extends IUser> getByUserIds(Collection<String> userIds)
    用户 ID 集合获取用户

  • IUser getByUsername(String username) (可选)
    根据用户名获取用户信息,默认内部调用getByUsernames实现

  • Iterator<? extends IUser> getByUsernames(Collection<String> usernames)
    根据用户名集合获取用户信息

  • Iterator<? extends IUser> getByGroupTypeAndGroupIds(String groupType, Collection<String> groupIds)
    通过组类型(枚举定义:com.dstz.org.api.enums.GroupType)和组 ID 集合获取用户

  • PageListDTO<? extends IUser> queryFilter(QueryParamDTO queryParamDTO)(可选)
    用于对接自定义对话框(userSelector: 用户选择),如自定义对话框(userSelector)选择的数据源方式可不实现

com.dstz.org.api.GroupApi

组接口,用于获取角色、岗位、组织等信息

  • IGroup getByGroupId(String groupType, String groupId)(可选)
    根据组类型和组 ID 获取组信息,默认内部调用getByGroupIds实现

  • Iterator<? extends IGroup> getByGroupIds(String groupType, Collection<String> groupIds)
    根据组类型和组 ID 集合获取组信息迭代器

  • IGroup getByGroupCode(String groupType, String groupCode)(可选)
    根据组类型和组编码获取组信息,默认内部调用getByGroupCodes实现

  • Iterator<? extends IGroup> getByGroupCodes(String groupType, Collection<String> groupCodes)
    根据组类型和租编码集合获取组信息迭代器

  • List<? extends IGroup> getByUserId(String userId)(可选)
    获取用户所关联组信息列表,默认将通过枚举com.dstz.org.api.enums.GroupType调用getByGroupTypeAndUserId获取

  • List<? extends IGroup> getByGroupTypeAndUserId(String groupType, String userId)
    根据组类型和用户 ID 获取所关联的组信息列表

  • List<? extends IGroup> queryFilter(String groupType, QueryParamDTO queryParamDTO)(可选)
    自定义对话框(orgSelector: 组织选择、postSelector: 岗位选择、roleSelector:角色选择)的实现,如自定义对话框已选择数据源方式可不实现。

方案一:客户端对接

客户端的对接,需要您在 AgileBPM 提供的微服务项目中实现相关接口,通过编写远程调用来实现数据交换。此种方案对企业已有服务无侵入性。

图示

会话整合

下面我们将通过一个JWT会话标识案例来开始我们的对接。

对接步骤

  1. 修改 com.dstz.cloud.user.api.RequestUserSessionApiImpl
java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

@Component
public class RequestUserSessionApiImpl implements UserSessionApi {

	@Override
	public IUserSession getSession() {
		HttpServletRequest request = Objects.requireNonNull(AbRequestUtils.getHttpServletRequest());
		// 从请求头中获取Token
		String token = request.getHeader("access-token");
		if (StrUtil.isEmpty(token)) {
			return null;
		}

		// 解析出存储信息
		Claims claims = Jwts.parser().setSigningKey("xxx").parseClaimsJws(token).getBody();

		DefaultUserSession userSession = new DefaultUserSession();

		// 用户相关

		// 用户ID
		userSession.setUserId(claims.get("userId", String.class));
		// 用户名
		userSession.setUsername(claims.get("username", String.class));
		// 用户姓名
		userSession.setFullName(claims.get("fullName", String.class));

		// 当前组织相关  可选;默认从 com.dstz.org.api.GroupApi.getByGroupTypeAndUserId 获取第一条数据

		// 组织ID
		userSession.setOrgId(claims.get("orgId", String.class));
		// 组织编码
		userSession.setOrgCode(claims.get("orgCode", String.class));
		// 组织名称
		userSession.setOrgName(claims.get("orgName", String.class));


		// 是否超级管理员 (可选,默认从从系统属性中a[admin.accounts]比对超级管理员用户名)
		userSession.setSuperAdmin(claims.get("superAdmin", Boolean.class));

		// 角色集合(可选,默认从 com.dstz.org.api.GroupApi.getByGroupTypeAndUserId 获取)
		userSession.setAuthorities(claims.get("authorities", List.class));


		return userSession;
	}
}
  1. 修改类文件
  • ab-cloud/ab-cloud-common/ab-cloud-autoconfigure/src/main/java/com/dstz/cloud/autoconfigure/client/AbCloudClientConfiguration.java 移除方法abSessionInfoTransform以及标注注解

  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/session/AbCloudSessionWebConfiguration.java 移除方法requestUserSessionApiImpl以及标注注解
    移除方法userSessionApiFetch以及标注注解

  1. 删除类文件
  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/fallback/UserSessionApiClientFallback.java
  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/client/UserSessionApiClient.java
  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/user/api/UserSessionApiFetchImpl.java
  • ab-cloud/ab-cloud-common/ab-cloud-autoconfigure/src/main/java/com/dstz/cloud/autoconfigure/client/AbSessionInfoTransform.java
  1. 配置转发 Token

ab-cloud/ab-cloud-bpm/ab-bpm-service/src/main/resources/application.yml

yaml
ab:
  # 客户端信息转发
  rest-client-info-transform:
    headers:
      - name: access-token

用户组织对接

在会话整合阶段,我们已经实现了会话信息的转发,此处无需再关注会话的传递。

1.编写 Feign 调用客户端

封装调用服务端接口的 Feign 客户端

  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/client/UserApiClient.java
  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/client/GroupApiClient.java

2. 转换数据

将 Feign 客户端调用返回数据转换为接口定义返回对象

  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/user/api/UserApiImpl.java
  • ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/user/api/GroupApiImpl.java

方案二:服务端对接

服务端对接,需要您在已有服务中引入 AgileBPM 提供的依赖,实现对应接口。

会话整合

对于网关转发的请求,BPM 会将当前会话标识请求带入到鉴权服务中,鉴权服务通过标识返回对应的用户信息

图示

  1. 配置会话转发

文件:ab-cloud/ab-cloud-bpm/ab-bpm-service/src/main/resources/application.yml

yaml
ab:
  rest-client-info-transform:
    headers:
      - name: Authorization
  1. 鉴权服务模块-引入依赖
xml
<dependency>
  <groupId>com.dstz</groupId>
  <artifactId>ab-cloud-session-endpoint</artifactId>
  <version>xxx</version>
</dependency>
  1. 鉴权服务模块-实现接口

com.dstz.cloud.session.api.UserSessionApi

  • IUserSession getSession()

    获取会话,您可以使用com.dstz.cloud.session.api.model.DefaultUserSession封装值返回

  1. 鉴权服务模块-注册 Bean

您可选择以下其中一种方式将 Bean 注入到 Spring 容器里

  • 导入
@Import({UserSessionApiEndpoint.class})
  • 包扫描
@ComponentScan(basePackages = {"com.dstz"})
  • @Bean
@Bean
public UserSessionApiEndpoint userSessionApiEndpoint(UserSessionApi userSessionApi){
	return new UserSessionApiEndpoint(userSessionApi);
}

用户组织

  1. 用户组织服务模块-引入依赖
xml
<dependency>
    <groupId>com.dstz</groupId>
    <artifactId>ab-cloud-usergroup-endpoint</artifactId>
    <version>xxx</version>
</dependency>
  1. 用户组织模块-实现接口
  • com.dstz.org.api.UserApi
  • com.dstz.org.api.GroupApi
  1. 注册 Bean

您可选择以下其中一种方式将 Bean 注入到 Spring 容器里

  • 导入
java
@Import({GroupApiEndpoint.class, UserApiEndpoint.class})
  • 包扫描
java
@ComponentScan(basePackages = {"com.dstz"})
  • @Bean
java
@Bean
public UserApiEndpoint userApiEndpoint(UserApi userApi) {
	return new UserApiEndpoint(userApi);
}
@Bean
public GroupApiEndpoint groupApiEndpoint(GroupApi groupApi) {
	return new GroupApiEndpoint(groupApi);
}

网关配置

配置网关路由,将 BPM 请求转发到 BPM 服务中

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: a5-bpm-service
          uri: lb://a5-bpm-service
          predicates:
            - Path=/ab-bpm/**

自定义对话框

您实现了上述定义的方法 com.dstz.org.api.UserApi#queryFiltercom.dstz.org.api.GroupApi#queryFilter,可跳过此节配置

系统页面中用到的组织对话框选择器,都利用系统的自定义对话框做了解偶,您可选择数据源的方式对组织对话框做适配。

1.删除旧纪录

数据库中执行 SQL 语句

sql
DELETE FROM biz_cust_dialog WHERE code_ IN ('userSelector', 'orgSelector', 'roleSelector', 'postSelector');

2.添加数据源

菜单:系统 > 系统数据源 > 数据源

图示

3.配置自定义对话框

菜单:视图 > 扩展配置 > 自定义对话框

图示

用户选择器(userSelector)

  1. 添加

图示

2 设置字段参数-显示字段

点击上图设置字段参数

显示字段非固定,用于展示使用,可有多个

图示

  1. 设置字段参数-条件字段

图示

  1. 设置字段参数-返回字段

返回字段,有左边的字段映射到右边字段名称上

  • id-用户 ID
  • name-用户姓名
  • account-用户账户

图示

  1. 确定并保存

  2. 预览对话框

图示

组织选择器(orgSelector)

  1. 添加

图示

  1. 设置字段参数-显示字段

填写字段映射

图示

  1. 设置字段参数-返回字段

将左侧的字段映射到规范定义返回字段

  • id-组织 ID
  • key-组织编码
  • name-组织名称

图示

  1. 确定并保存

  2. 预览对话框

图示

角色选择器(roleSelector)

配置上与前两选择器类似,在设置字段参数-返回字段上约定如下

  • id-角色 ID
  • key-角色编码
  • name-角色名称

岗位选择器(postSelector)

配置上与前两选择器类似,在设置字段参数-返回字段上约定如下

  • id-岗位 ID
  • key-岗位编码
  • name-岗位名称

常见问题

  1. 使用的RestTemplate方式调用远程接口会传递会话吗?
    回答:会的,AgileBPM 实现了与 Feign 同样的拦截器,按上述配置的会话字段自动转发。

  2. 自定义对话框中无法使用多表,如何配置出岗位关联?
    回答:自定义对话框支持使用数据源接口方式,通过 JdbcTemplate 查询关联表并返回结果,此代码需要的 BPM 服务中编写。详细参考自定义对话框篇配置。

用户组织对接 has loaded