流程发起人与当前审批人是两种身份。前者回答“谁发起了这次流程”,后者回答“现在由谁处理任务”。设置节点的 assignee,不能代替设置流程发起人。
BPMN 中先定义发起人变量
开始事件可以通过 activiti:initiator 指定保存发起人身份的变量名。以下是片段,activiti 前缀需要在完整 BPMN 的 definitions 上声明对应命名空间:
<startEvent id="start" name="开始" activiti:initiator="applyUserId"/>
这里的 applyUserId 是变量名,不需要写成 ${applyUserId}。它和后续用户任务上引用变量的表达式用途不同。
引擎层的身份入口
在 Activiti 7.1.0.M6 中,可以找到:
org.activiti.engine.impl.identity.Authentication
这个类提供 setAuthenticatedUserId 和 getAuthenticatedUserId,内部使用线程绑定状态。对应版本源码
如果直接调用该版本的引擎层启动流程,可以按下面的顺序组织。假设 runtimeService 已注入,trustedUserId 来自服务端已认证身份,variables 是本次流程的变量:
import org.activiti.engine.impl.identity.Authentication;
String previousUser = Authentication.getAuthenticatedUserId();
try {
Authentication.setAuthenticatedUserId(trustedUserId);
org.activiti.engine.runtime.ProcessInstance instance =
runtimeService.startProcessInstanceByKey(
processDefinitionKey, businessKey, variables);
} finally {
Authentication.setAuthenticatedUserId(previousUser);
}
保存并恢复之前的值,比在正常路径末尾简单清空更能兼顾异常和嵌套调用。这一写法不把该状态当作跨线程身份传播机制;异步任务应显式建立自己的受信任身份上下文。
为什么要在启动前设置
流程启动时,引擎才有机会把当前身份记录为发起人,并根据开始事件配置生成相应流程变量。等到任务已经创建,再设置当前线程的身份,不会自动补写过去的发起信息。
对于启用了对应历史记录的实例,可以通过历史流程查询查看 startUserId。变量 applyUserId 与历史字段是不同载体:变量服务于流程表达式和业务逻辑,历史字段用于记录发起身份,不应仅因其中一个有值就忽略另一个的生成规则。
集成 Spring Security 时的边界
如果使用 Activiti 的高层运行时 API 或 Spring Security 集成,身份可能已由框架适配。不要为了设置发起人,随意覆盖当前安全上下文;先明确调用的是引擎层还是集成后的入口,并使用该入口约定的身份机制。
无论采用哪种方式,发起人 ID 都不应直接信任请求参数。服务端应从登录身份取得它,避免用户把别人的账号填成发起人。流程启动后再核对实际记录,才能确认“身份设置—流程启动—历史查询”这条链路一致。