1.2 spring security在activiti中的应用

spring security在activiti中的应用 #

1.1 流程部署 #

Spring Security主要在以下几个场景中起作用:

  1. 用户认证与授权 通过UserDetailsService实现用户认证,如ApplicationConfiguration类中的myUserDetailsService()方法 使用SecurityManager进行安全管理,如LocalSpringSecurityManager类 通过SecurityContextPrincipalProvider获取当前认证用户信息
  2. 流程安全策略管理 通过ProcessSecurityPoliciesManager实现流程定义和实例的访问控制 使用SecurityPoliciesRestrictionApplier限制流程查询范围
  3. 方法级安全控制 通过ActivitiMethodSecurityAutoConfiguration启用全局方法安全 支持@PreAuthorize、@Secured等注解进行方法级权限控制
  4. 用户角色与权限管理 通过PrincipalRolesProvider和PrincipalGroupsProvider管理用户角色和组 使用GrantedAuthoritiesResolver解析用户权限
  5. REST API安全 通过EndpointAutoConfiguration配置Actuator端点安全 保护流程引擎相关API的访问
  6. 测试环境安全模拟 使用SecurityUtil类在测试中模拟用户登录 通过@WithMockUser等注解进行测试用户模拟
  7. 安全策略配置 通过SecurityPoliciesProperties配置安全策略 支持基于用户、组、服务名称和流程key的访问控制 这些安全机制共同构成了工程的安全体系,确保系统资源和业务流程的访问受到适当控制。

1.1.1 用户认证与授权 #

@PreAuthorize("hasRole('ACTIVITI_USER')")
public class TaskRuntimeImpl implements TaskRuntime {
graph TD
    A[调用TaskRuntimeImpl方法] --> B{Spring Security拦截器}
    B -->|是| C[获取当前认证信息]
    B -->|否| D[继续执行方法]
    C --> E{是否已认证?}
    E -->|是| F{是否有ACTIVITI_USER角色?}
    E -->|否| G[抛出AccessDeniedException]
    F -->|是| H[继续执行方法]
    F -->|否| I[抛出AccessDeniedException]

详细执行流程:

  1. 方法调用:当调用TaskRuntimeImpl中的任何方法时,Spring Security的AOP拦截器会首先执行。
  2. 认证检查: 通过SecurityContextHolder.getContext().getAuthentication()获取当前认证信息 检查用户是否已认证(authentication.isAuthenticated())
  3. 角色验证: 从Authentication对象中获取用户权限(getAuthorities()) 检查权限集合中是否包含ROLE_ACTIVITI_USER
  4. 决策执行: 如果用户拥有ACTIVITI_USER角色,允许方法继续执行 如果用户没有该角色,抛出AccessDeniedException异常
  5. 异常处理: Spring Security会将AccessDeniedException转换为HTTP 403 Forbidden响应(在Web应用中)

1.1.1.1 在Spring Security中,用户认证与授权后的数据过滤主要通过以下几种方式实现 #

  1. 方法级安全控制:
  • 使用@PreAuthorize注解进行方法调用前的权限验证
  • 示例:@PreAuthorize(“hasRole(‘ACTIVITI_USER’)")确保只有拥有ACTIVITI_USER角色的用户才能访问方法
  1. 查询级数据过滤:
  • 在数据库查询时根据当前用户信息进行过滤
@Override
public Page<Task> tasks(Pageable pageable) {
    String authenticatedUserId = securityManager.getAuthenticatedUserId();
    if (authenticatedUserId != null && !authenticatedUserId.isEmpty()) {
        List<String> userGroups = securityManager.getAuthenticatedUserGroups();
        return tasks(pageable,
                TaskPayloadBuilder.tasks().withAssignee(authenticatedUserId).withGroups(userGroups).build());
    }
    throw new IllegalStateException("You need an authenticated user to perform a task query");
}
  1. 业务逻辑级过滤:
  • 在业务逻辑中根据用户权限进行数据过滤
private List<IdentityLink> getIdentityLinks(String taskId) {
    String authenticatedUserId = securityManager.getAuthenticatedUserId();
    if (authenticatedUserId != null && !authenticatedUserId.isEmpty()) {
        List<String> userRoles = securityManager.getAuthenticatedUserRoles();
        List<String> userGroups = securityManager.getAuthenticatedUserGroups();
        org.activiti.engine.task.Task internalTask = taskService.createTaskQuery()
            .taskCandidateOrAssigned(authenticatedUserId, userGroups)
            .taskId(taskId)
            .singleResult();
        if (internalTask == null) {
            throw new NotFoundException("Unable to find task for the given id: " + taskId);
        }
        return taskService.getIdentityLinksForTask(taskId);
    }
    throw new IllegalStateException("There is no authenticated user, we need a user authenticated to find tasks");
}
  1. 数据访问层过滤:
  • 在数据访问层根据用户权限进行数据过滤
  • 使用Spring Data JPA的@Query注解或Specification进行过滤
  1. 视图层过滤:
  • 在视图层根据用户权限显示或隐藏某些数据
  • 使用Thymeleaf或JSP等模板引擎的security标签进行控制

1.1.2 流程安全策略管理

graph TD
    A[用户请求] --> B{是否认证?}
    B -->|是| C[获取安全上下文]
    B -->|否| D[重定向到登录页]
    C --> E{是否有权限?}
    E -->|是| F[执行请求]
    E -->|否| G[返回403错误]

在Activiti工程中,流程安全策略主要通过ProcessSecurityPoliciesManager接口及其实现类来管理。以下是核心实现和具体使用逻辑:

  1. 流程定义访问: 用户请求访问流程定义时,首先检查canRead权限 如果用户没有读取权限,抛出ActivitiObjectNotFoundException
  2. 流程实例访问: 用户请求访问流程实例时,检查canRead权限 同时验证用户是否是流程启动者或任务参与者 如果权限不足,抛出ActivitiObjectNotFoundException
  3. 流程操作权限: 用户尝试启动、挂起、恢复、删除流程时,检查canWrite权限 如果用户没有写权限,抛出ActivitiForbiddenException
  4. 查询过滤: 在查询流程定义和实例时,通过restrictProcessDefQuery和restrictProcessInstQuery方法过滤结果 只返回用户有权限访问的流程定义和实例