摘要:文旅后台存在管理员、计调、带队导游、售后等多角色,不同角色需严格隔离团期、订单、游客数据。传统角色权限仅控制菜单,无法解决数据越权查看、跨团队数据泄露问题。本文基于 SpringSecurity+JWT 实现文旅业务专属细粒度数据权限,通过自定义数据权限注解+SQL动态过滤,实现多角色精准数据隔离,满足文旅数据安全与等保合规要求。
关键词:SpringSecurity;JWT;数据权限;文旅系统;多角色隔离;越权防护
一、文旅业务核心技术痛点
- 导游仅可查看自己带队团期,无数据权限隔离会导致全员数据泄露;
- 计调只能操作负责线路,越权查询易造成订单、隐私数据外泄;
- 传统RBAC菜单权限粒度太粗,无法实现行级数据隔离,存在严重安全漏洞。
二、整体设计思路 - JWT令牌携带用户角色、所属团队、数据权限标识;
- 自定义文旅数据权限注解,切入Mapper层;
- 基于Mybatis拦截器动态拼接过滤SQL,实现行级数据隔离;
- 超级管理员全量可见,普通角色严格匹配所属数据范围。
三、核心代码实现 - 自定义数据权限注解
java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TourDataScope {
// 数据权限表别名
String alias() default "";
}
- JWT用户权限载体实体
java
@Data
public class TourUserAuth {
// 用户ID
private Long userId;
// 角色标识:admin/operator/guide
private String role;
// 负责团队ID
private Long teamId;
}
- Mybatis数据权限拦截器(核心)
java
@Component
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class})})
@Slf4j
public class TourDataScopeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取当前登录用户权限信息
TourUserAuth auth = SecurityUtil.getAuthUser();
// 超级管理员放行
if("admin".equals(auth.getRole())){
return invocation.proceed();
}
// 非管理员动态拼接数据过滤条件:仅查询自己团队数据
StatementHandler handler = (StatementHandler) invocation.getTarget();
String sql = handler.getBoundSql().getSql();
String newSql = sql + " AND team_id = " + auth.getTeamId();
// 重写SQL实现数据隔离
ReflectUtil.setFieldValue(handler.getBoundSql(),"sql",newSql);
return invocation.proceed();
}
}
- Mapper层使用
java
public interface TourGroupMapper {
@Select("select * from tour_group")
@TourDataScope(alias = "tg")
List<TourGroup> selectGroupList();
}
四、业务落地价值
- 杜绝数据越权:从SQL层强制隔离不同角色数据,修复文旅系统数据安全漏洞;
- 权限粒度精细化:区别于传统菜单权限,实现行级数据精准控制;
- 合规性提升:满足文旅用户隐私数据隔离要求,贴合等保数据安全规范;
- 低侵入高扩展:注解式开发,无需改动大量业务代码,可快速适配订单、团期、售后全模块。
五、总结
多数文旅系统仅实现菜单权限控制,存在极大数据安全隐患。基于Mybatis拦截器+JWT实现的数据权限方案,可低成本完成多角色数据隔离,是文旅后台标准化、安全化落地的刚需技术方案,可直接投产使用。
声明:本文为乐启国际旅行社有限公司算法技术实战复盘,仅用于技术交流与行业数字化落地参考。