当前位置: 首页 > news >正文

达州住房和城乡建设部网站/seo优化网站查询

达州住房和城乡建设部网站,seo优化网站查询,saas建站没有网站源代码么,手表哪个网站正品前言 在企业级应用中,数据权限控制是保证数据安全的重要环节。本文将详细介绍如何在 Spring Boot 3.4.3 项目中结合 JSqlParser 和 MyBatis 实现灵活的数据权限控制,通过动态 SQL 改写实现多租户、部门隔离等常见数据权限需求。 一、环境准备 确保开发…

前言

在企业级应用中,数据权限控制是保证数据安全的重要环节。本文将详细介绍如何在 Spring Boot 3.4.3 项目中结合 JSqlParser 和 MyBatis 实现灵活的数据权限控制,通过动态 SQL 改写实现多租户、部门隔离等常见数据权限需求。

一、环境准备

确保开发环境满足以下要求:

  • JDK 17+
  • Spring Boot 3.4.3
  • MyBatis 3.5.13+
  • JSqlParser 4.5+
  • Maven 3.6.3+

二、项目配置

1. 添加依赖

pom.xml 中添加以下依赖:

<dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><!-- JSqlParser --><dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>4.6</version></dependency><!-- 数据库驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- 其他工具 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

2. 数据权限注解

定义数据权限注解:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataPermission {/*** 部门表别名*/String deptAlias() default "";/*** 用户表别名*/String userAlias() default "";/*** 权限类型*/DataPermissionType type() default DataPermissionType.DEPT;
}public enum DataPermissionType {/*** 全部数据权限*/ALL,/*** 部门数据权限*/DEPT,/*** 部门及以下数据权限*/DEPT_AND_CHILD,/*** 仅本人数据权限*/SELF
}

三、核心实现

1. 数据权限上下文

public class DataPermissionContext {private static final ThreadLocal<DataPermissionInfo> CONTEXT = new ThreadLocal<>();public static void set(DataPermissionInfo info) {CONTEXT.set(info);}public static DataPermissionInfo get() {return CONTEXT.get();}public static void clear() {CONTEXT.remove();}
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class DataPermissionInfo {private Long userId;private Long deptId;private List<Long> deptIds; // 用户拥有的部门权限private DataPermissionType permissionType;
}

2. SQL 解析改写拦截器

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
@Slf4j
public class DataPermissionInterceptor implements Interceptor {private final JSqlParser sqlParser = new JSqlParser();@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaObject = SystemMetaObject.forObject(statementHandler);// 获取Mapper方法上的DataPermission注解MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");String id = mappedStatement.getId();String className = id.substring(0, id.lastIndexOf("."));String methodName = id.substring(id.lastIndexOf(".") + 1);Method method = Class.forName(className).getMethod(methodName, mappedStatement.getParameterMap().getParameterTypes());DataPermission dataPermission = method.getAnnotation(DataPermission.class);if (dataPermission == null) {return invocation.proceed();}// 获取原始SQLBoundSql boundSql = statementHandler.getBoundSql();String originalSql = boundSql.getSql();// 解析并改写SQLString modifiedSql = processSql(originalSql, dataPermission);// 设置改写后的SQLmetaObject.setValue("delegate.boundSql.sql", modifiedSql);return invocation.proceed();}private String processSql(String sql, DataPermission dataPermission) throws JSQLParserException {DataPermissionInfo permissionInfo = DataPermissionContext.get();if (permissionInfo == null || permissionInfo.getPermissionType() == DataPermissionType.ALL) {return sql;}Statement statement = sqlParser.parse(sql);if (statement instanceof Select) {Select select = (Select) statement;PlainSelect plainSelect = (PlainSelect) select.getSelectBody();// 构建权限条件Expression permissionExpression = buildPermissionExpression(dataPermission, permissionInfo);if (permissionExpression != null) {if (plainSelect.getWhere() == null) {plainSelect.setWhere(permissionExpression);} else {plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), permissionExpression));}}return select.toString();}return sql;}private Expression buildPermissionExpression(DataPermission dataPermission, DataPermissionInfo permissionInfo) {DataPermissionType type = permissionInfo.getPermissionType();if (type == DataPermissionType.SELF && StringUtils.isNotBlank(dataPermission.userAlias())) {// 仅本人数据权限return new EqualsTo(new Column(dataPermission.userAlias() + ".user_id"),new LongValue(permissionInfo.getUserId()));} else if ((type == DataPermissionType.DEPT || type == DataPermissionType.DEPT_AND_CHILD) && StringUtils.isNotBlank(dataPermission.deptAlias())) {// 部门数据权限if (CollectionUtils.isEmpty(permissionInfo.getDeptIds())) {return null;}if (type == DataPermissionType.DEPT) {// 仅本部门return new InExpression(new Column(dataPermission.deptAlias() + ".dept_id"),new ExpressionList(permissionInfo.getDeptIds().stream().map(LongValue::new).collect(Collectors.toList())));} else {// 本部门及以下部门return new GreaterThanEquals(new Column(dataPermission.deptAlias() + ".dept_path"),new StringValue(permissionInfo.getDeptId() + "/%"));}}return null;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 可配置化处理}
}

3. 注册拦截器

@Configuration
public class MyBatisConfig {@Beanpublic DataPermissionInterceptor dataPermissionInterceptor() {return new DataPermissionInterceptor();}
}

四、使用示例

1. 设置数据权限上下文

@RestControllerAdvice
public class DataPermissionAdvice {@ModelAttributepublic void setDataPermission() {// 实际项目中应从登录用户信息中获取DataPermissionInfo info = new DataPermissionInfo();info.setUserId(1001L);info.setDeptId(10L);info.setDeptIds(Arrays.asList(10L, 11L, 12L));info.setPermissionType(DataPermissionType.DEPT_AND_CHILD);DataPermissionContext.set(info);}
}

2. Mapper 接口使用

public interface UserMapper {@DataPermission(deptAlias = "u", userAlias = "u")@Select("SELECT * FROM sys_user u")List<User> selectAllUsers();@DataPermission(deptAlias = "u", type = DataPermissionType.SELF)@Select("SELECT * FROM sys_user u WHERE u.status = 1")List<User> selectActiveUsers();
}

3. 实体类定义

@Data
public class User {private Long userId;private String username;private Long deptId;private Integer status;// 其他字段...
}

五、高级功能

1. 多表关联查询支持

public interface OrderMapper {@DataPermission(deptAlias = "u", userAlias = "u")@Select("SELECT o.*, u.username FROM sys_order o " +"LEFT JOIN sys_user u ON o.user_id = u.user_id")List<Order> selectAllOrders();
}

2. 自定义权限处理器

public interface DataPermissionHandler {Expression handle(DataPermission dataPermission, DataPermissionInfo permissionInfo);
}@Component
public class DefaultDataPermissionHandler implements DataPermissionHandler {@Overridepublic Expression handle(DataPermission dataPermission, DataPermissionInfo permissionInfo) {// 自定义权限逻辑return null;}
}// 在拦截器中注入使用
public class DataPermissionInterceptor implements Interceptor {@Autowiredprivate DataPermissionHandler permissionHandler;// ...其他代码
}

3. 动态表名支持

public class DynamicTableProcessor {public static String process(String sql, String tableName, String dynamicTableName) {try {Statement statement = CCJSqlParserUtil.parse(sql);if (statement instanceof Select) {Select select = (Select) statement;select.getSelectBody().accept(new TableNamesFinder() {@Overridepublic void visit(Table table) {if (table.getName().equalsIgnoreCase(tableName)) {table.setName(dynamicTableName);}}});return select.toString();}} catch (JSQLParserException e) {log.error("动态表名处理失败", e);}return sql;}
}

六、最佳实践

  1. 权限粒度控制

    • 根据业务需求设计合理的权限粒度
    • 避免过度设计导致系统复杂度过高
  2. 性能考虑

    • 大数据量表添加合适的索引
    • 复杂权限条件考虑使用视图
  3. 缓存策略

    • 频繁使用的权限数据可适当缓存
    • 注意缓存与权限变更的同步
  4. 测试覆盖

    • 编写全面的测试用例验证SQL改写正确性
    • 覆盖各种权限组合场景
  5. 日志记录

    • 记录重要的权限过滤操作
    • 便于问题排查和审计

七、常见问题解决

  1. SQL解析失败

    • 检查SQL语法是否符合JSqlParser支持的标准
    • 复杂SQL考虑简化或拆分
  2. 权限泄露

    • 确保所有查询方法都经过权限过滤
    • 默认拒绝所有未明确授权的访问
  3. 性能下降

    • 检查生成的SQL执行计划
    • 优化权限条件涉及的字段索引
  4. 嵌套查询支持

    • 复杂嵌套查询可能需要特殊处理
    • 考虑使用子查询或临时表优化

八、总结

本文详细介绍了在 Spring Boot 3.4.3 项目中基于 JSqlParser 和 MyBatis 实现自定义数据权限的完整方案。通过这种方案,我们可以:

  1. 通过注解灵活控制数据权限范围
  2. 自动改写SQL实现无缝权限过滤
  3. 支持多种常见的权限控制模式
  4. 保持业务代码的简洁性
  5. 实现细粒度的数据访问控制

这种方案相比传统的在业务代码中添加权限条件的方式,具有更好的可维护性和一致性,能够有效降低数据权限泄露的风险,是企业级应用开发中数据安全控制的理想选择。

http://www.cadmedia.cn/news/711.html

相关文章:

  • 超酷win8风格企业网站织梦模板/软文推广渠道主要有
  • 太仓建设银行网站/济南网站推广
  • 青海西宁制作网站专业/广东seo点击排名软件哪里好
  • 建设银行官方网站/有哪些可以推广的平台
  • 河南郑州汽车网网站建设/seo优化软件免费
  • 网站建设赠送seo/怎么提高百度搜索排名
  • 做网站网页的工作怎么样/足球排行榜前十名
  • 梁山网站建设/网络推广服务合同
  • 汕头网站建设套餐/全国知名网站排名
  • 大理建设学校官方网站/网站设计方案模板
  • 全网营销系统是不是传销/西安seo诊断
  • 电子外发加工网/长春网站优化流程
  • 四川省建设工程质量监理协会网站/什么是网络营销策略
  • 网站开发制作云盘/软文广告经典案例300
  • 做网站买什么香港服务器/网络广告策划案例
  • 政府网站建设制度/友链交易
  • 网站持有者和备案企业/网站运营包括哪些内容
  • 汕头手机建站模板/设计网站官网
  • 中国建设银行网站保定五四路/指数网站
  • 政府网站建设管理 书/阿里指数怎么没有了
  • 装修公司网站建设方案/网站搭建一般要多少钱
  • 沧州响应式网站开发/优化大师客服
  • 苏州网站seo/百度关键词优化公司哪家好
  • 广告公司网站策划/网站流量分析的指标有哪些
  • 品牌企业网站建设公司/宁波seo排名方案优化公司
  • 网站上文章字体部分复制怎么做的/武汉seo网络营销推广
  • 织梦网站首页栏目修改/网站首页模板
  • app开发软件怎么做/成都关键词优化平台
  • 丰台周边网站建设/怎么在百度推广
  • wordpress调用url图片路径/武汉做seo公司