线上与测试环境excel导出列不同
  1. 在用户有查看年龄权限时,年龄列有列名但无法展示。

线上导出表格为

姓名年龄手机号
张三13111112323
李四14222223434

线下导出表格为

姓名年龄手机号
张三1813111112323
李四2014222223434
  1. 用户无查看年龄权限时,正常屏蔽年龄列

线上导出表格为

姓名手机号
张三13111112323
李四14222223434

线下导出表格为

姓名手机号
张三13111112323
李四14222223434

在无权限时正常屏蔽。

问题定位

代码具体逻辑为先查询500条数据开始写入excel,在写入excel的时候预查询下一批需要写入的数据

public void export(...) { boolean canViewAge = isAuthorizationViewAgeUser(); // 主线程判断 ExcelUtils.exportData(..., userService::queryPage, // 异步线程查询+映射 writer -> { if (!canViewAge) { // 主线程控制列 writer.includeColumnFieldNames(fieldNamesExcluding(..., "age")); } }, 500 ); }

根因

权限判断与数据脱敏不在同一线程上下文:

  • 表头列控制使用的是主线程的canViewAge(因此保留年龄列)
  • 数据查询在异步线程执行,异步线程无法稳定获取SecurityContext
  • 导致异步线程判断该用户无权限,将年龄字段置空

触发条件

导出采用分批异步预查询(每批500条)

  1. 主线程先判断权限 canViewAge
  2. 开始写当前批Excel
  3. 同时在线程池异步预查询下一批数据

修复

public void export(...) { canViewAge = isAuthorizationViewAgeUser(); exportData( query, writerCustomizer -> { if (!canViewAge) { writer.includeColumnFieldNames(fieldNamesExcluding(ExportData.class, "age")); } }, (q, pageNum, pageSize) -> queryPage(q, pageNum, pageSize, canViewAge), // 显式透传 500 );