Skip to content

Commit 8b2b779

Browse files
committedSep 17, 2020
新增数据权限处理器
1 parent 8b8ee16 commit 8b2b779

File tree

7 files changed

+204
-0
lines changed

7 files changed

+204
-0
lines changed
 

‎mybatis-plus-annotation/src/main/java/com/baomidou/mybatisplus/annotation/InterceptorIgnore.java

+5
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,9 @@
4040
* 垃圾SQL拦截 {@link com.baomidou.mybatisplus.extension.plugins.inner.IllegalSQLInnerInterceptor}
4141
*/
4242
String illegalSql() default "";
43+
44+
/**
45+
* 数据权限 {@link com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor}
46+
*/
47+
String dataPermission() default "";
4348
}

‎mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/plugins/InterceptorIgnoreHelper.java

+5
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ public static boolean willIgnoreIllegalSql(String id) {
7474
return willIgnore(id, i -> i.getIllegalSql() != null && i.getIllegalSql());
7575
}
7676

77+
public static boolean willIgnoreDataPermission(String id) {
78+
return willIgnore(id, i -> i.getDataPermission() != null && i.getDataPermission());
79+
}
80+
7781
public static boolean willIgnore(String id, Function<InterceptorIgnoreCache, Boolean> function) {
7882
InterceptorIgnoreCache cache = INTERCEPTOR_IGNORE_CACHE.get(id);
7983
if (cache != null) {
@@ -130,5 +134,6 @@ public static class InterceptorIgnoreCache {
130134
private Boolean dynamicTableName;
131135
private Boolean blockAttack;
132136
private Boolean illegalSql;
137+
private Boolean dataPermission;
133138
}
134139
}

‎mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/parser/JsqlParserSupport.java

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import org.apache.ibatis.logging.LogFactory;
1515

1616
/**
17+
* https://github.com/JSQLParser/JSqlParser
18+
*
1719
* @author miemie
1820
* @since 2020-06-22
1921
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (c) 2011-2020, baomidou (jobob@qq.com).
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.baomidou.mybatisplus.extension.plugins.handler;
17+
18+
import net.sf.jsqlparser.expression.Expression;
19+
20+
/**
21+
* 数据权限处理器
22+
*
23+
* @author hubin
24+
* @since 3.4.1 +
25+
*/
26+
public interface DataPermissionHandler {
27+
28+
/**
29+
* 获取数据权限 SQL 片段
30+
*
31+
* @param where 待执行 SQL Where 条件表达式
32+
* @param mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法
33+
* @return JSqlParser 条件表达式
34+
*/
35+
Expression getSqlSegment(Expression where, String mappedStatementId);
36+
}

‎mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/handler/TableNameHandler.java

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package com.baomidou.mybatisplus.extension.plugins.handler;
1717

1818
/**
19+
* 动态表名处理器
20+
*
1921
* @author miemie
2022
* @since 3.4.0
2123
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2011-2020, baomidou (jobob@qq.com).
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.baomidou.mybatisplus.extension.plugins.inner;
17+
18+
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
19+
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
20+
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
21+
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
22+
import lombok.*;
23+
import net.sf.jsqlparser.expression.Expression;
24+
import net.sf.jsqlparser.statement.select.PlainSelect;
25+
import net.sf.jsqlparser.statement.select.Select;
26+
import org.apache.ibatis.executor.Executor;
27+
import org.apache.ibatis.mapping.BoundSql;
28+
import org.apache.ibatis.mapping.MappedStatement;
29+
import org.apache.ibatis.session.ResultHandler;
30+
import org.apache.ibatis.session.RowBounds;
31+
32+
import java.sql.SQLException;
33+
34+
/**
35+
* 数据权限处理器
36+
*
37+
* @author hubin
38+
* @since 3.4.1 +
39+
*/
40+
@Data
41+
@NoArgsConstructor
42+
@AllArgsConstructor
43+
@ToString(callSuper = true)
44+
@EqualsAndHashCode(callSuper = true)
45+
@SuppressWarnings({"rawtypes"})
46+
public class DataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor {
47+
private DataPermissionHandler dataPermissionHandler;
48+
49+
@Override
50+
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
51+
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) return;
52+
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
53+
mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
54+
}
55+
56+
@Override
57+
protected void processSelect(Select select, int index, String sql, Object obj) {
58+
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
59+
Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), (String) obj);
60+
if (null != sqlSegment) {
61+
plainSelect.setWhere(sqlSegment);
62+
}
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.baomidou.mybatisplus.extension.plugins.inner;
2+
3+
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
4+
import net.sf.jsqlparser.JSQLParserException;
5+
import net.sf.jsqlparser.expression.Expression;
6+
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
7+
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
8+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
9+
import org.junit.jupiter.api.Test;
10+
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
14+
import static org.assertj.core.api.Assertions.assertThat;
15+
16+
/**
17+
* 数据权限拦截器测试
18+
*
19+
* @author hubin
20+
* @since 3.4.1 +
21+
*/
22+
public class DataPermissionInterceptorTest {
23+
private static String TEST_1 = "com.baomidou.userMapper.selectByUsername";
24+
private static String TEST_2 = "com.baomidou.userMapper.selectById";
25+
private static String TEST_3 = "com.baomidou.roleMapper.selectByCompanyId";
26+
private static String TEST_4 = "com.baomidou.roleMapper.selectById";
27+
28+
/**
29+
* 这里可以理解为数据库配置的数据权限规则 SQL
30+
*/
31+
private static Map<String, String> sqlSegmentMap = new HashMap<String, String>() {
32+
{
33+
put(TEST_1, "username='123' or userId IN (1,2,3)");
34+
put(TEST_2, "u.state=1 and u.amount > 1000");
35+
put(TEST_3, "companyId in (1,2,3)");
36+
put(TEST_4, "username like 'abc%'");
37+
}
38+
};
39+
40+
private static DataPermissionInterceptor interceptor = new DataPermissionInterceptor(new DataPermissionHandler() {
41+
42+
@Override
43+
public Expression getSqlSegment(Expression where, String mappedStatementId) {
44+
try {
45+
String sqlSegment = sqlSegmentMap.get(mappedStatementId);
46+
Expression sqlSegmentExpression = CCJSqlParserUtil.parseCondExpression(sqlSegment);
47+
if (null != where) {
48+
System.out.println("原 where = " + where.toString());
49+
if (mappedStatementId.equals(TEST_4)) {
50+
// 这里测试返回 OR 条件
51+
return new OrExpression(where, sqlSegmentExpression);
52+
}
53+
return new AndExpression(where, sqlSegmentExpression);
54+
}
55+
return sqlSegmentExpression;
56+
} catch (JSQLParserException e) {
57+
e.printStackTrace();
58+
}
59+
return null;
60+
}
61+
});
62+
63+
@Test
64+
void test1() {
65+
assertSql(TEST_1, "select * from sys_user",
66+
"SELECT * FROM sys_user WHERE username = '123' OR userId IN (1, 2, 3)");
67+
}
68+
69+
@Test
70+
void test2() {
71+
assertSql(TEST_2, "select u.username from sys_user u join sys_user_role r on u.id=r.user_id where r.role_id=3",
72+
"SELECT u.username FROM sys_user u JOIN sys_user_role r ON u.id = r.user_id WHERE r.role_id = 3 AND u.state = 1 AND u.amount > 1000");
73+
}
74+
75+
@Test
76+
void test3() {
77+
assertSql(TEST_3, "select * from sys_role where company_id=6",
78+
"SELECT * FROM sys_role WHERE company_id = 6 AND companyId IN (1, 2, 3)");
79+
}
80+
81+
@Test
82+
void test4() {
83+
assertSql(TEST_4, "select * from sys_role where id=3",
84+
"SELECT * FROM sys_role WHERE id = 3 OR username LIKE 'abc%'");
85+
}
86+
87+
void assertSql(String mappedStatementId, String sql, String targetSql) {
88+
assertThat(interceptor.parserSingle(sql, mappedStatementId)).isEqualTo(targetSql);
89+
}
90+
}

0 commit comments

Comments
 (0)
Please sign in to comment.