Skip to content

Commit c32498b

Browse files
committed
操作方法 Operation 新增 MUST 和 REFUSE 分别替代 NECESSARY 和 DISALLOW;解决 Structure.sqlVerify 不可用及预防可能的 SQL 注入;解决 SQLConfig 自定义的 idKey 和 userIdKey 在 Structure 中未同步导致自定义值校验不通过;
1 parent 9e501d4 commit c32498b

File tree

5 files changed

+259
-58
lines changed

5 files changed

+259
-58
lines changed

APIJSONORM/src/main/java/apijson/orm/AbstractParser.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import apijson.RequestMethod;
3535
import apijson.RequestRole;
3636
import apijson.StringUtil;
37+
import apijson.orm.AbstractSQLConfig.IdCallback;
3738
import apijson.orm.exception.ConditionErrorException;
3839
import apijson.orm.exception.ConflictException;
3940
import apijson.orm.exception.NotExistException;
@@ -43,7 +44,7 @@
4344
/**parser for parsing request to JSONObject
4445
* @author Lemon
4546
*/
46-
public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>, VerifierCreator<T>, SQLCreator {
47+
public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>, VerifierCreator<T>, SQLCreator, IdCallback {
4748
protected static final String TAG = "AbstractParser";
4849

4950

@@ -490,11 +491,25 @@ public JSONObject parseCorrectRequest(RequestMethod method, String tag, int vers
490491

491492
//获取指定的JSON结构 >>>>>>>>>>>>>>
492493

494+
493495
//JSONObject clone 浅拷贝没用,Structure.parse 会导致 structure 里面被清空,第二次从缓存里取到的就是 {}
494-
return Structure.parseRequest(method, name, target, request, maxUpdateCount, creator);
496+
return Structure.parseRequest(method, name, target, request, maxUpdateCount, getGlobleDatabase(), getGlobleSchema(), this, creator);
495497
}
496498

497-
499+
@Override
500+
public String getIdKey(String database, String schema, String table) {
501+
return apijson.JSONObject.KEY_ID;
502+
}
503+
@Override
504+
public String getUserIdKey(String database, String schema, String table) {
505+
return apijson.JSONObject.KEY_USER_ID;
506+
}
507+
@Override
508+
public Object newId(RequestMethod method, String database, String schema, String table) {
509+
return System.currentTimeMillis();
510+
}
511+
512+
498513
/**新建带状态内容的JSONObject
499514
* @param code
500515
* @param msg

APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import static apijson.JSONObject.KEY_ID;
1717
import static apijson.JSONObject.KEY_JSON;
1818
import static apijson.JSONObject.KEY_ORDER;
19-
import static apijson.JSONObject.KEY_ROLE;
2019
import static apijson.JSONObject.KEY_RAW;
20+
import static apijson.JSONObject.KEY_ROLE;
2121
import static apijson.JSONObject.KEY_SCHEMA;
2222
import static apijson.JSONObject.KEY_USER_ID;
2323
import static apijson.RequestMethod.DELETE;
@@ -48,20 +48,28 @@
4848
import com.alibaba.fastjson.annotation.JSONField;
4949

5050
import apijson.JSON;
51+
import apijson.JSONResponse;
5152
import apijson.Log;
5253
import apijson.NotNull;
5354
import apijson.RequestMethod;
5455
import apijson.RequestRole;
5556
import apijson.SQL;
5657
import apijson.StringUtil;
5758
import apijson.orm.exception.NotExistException;
59+
import apijson.orm.model.Access;
5860
import apijson.orm.model.Column;
61+
import apijson.orm.model.Document;
5962
import apijson.orm.model.ExtendedProperty;
63+
import apijson.orm.model.Function;
6064
import apijson.orm.model.PgAttribute;
6165
import apijson.orm.model.PgClass;
66+
import apijson.orm.model.Request;
67+
import apijson.orm.model.Response;
6268
import apijson.orm.model.SysColumn;
6369
import apijson.orm.model.SysTable;
6470
import apijson.orm.model.Table;
71+
import apijson.orm.model.Test;
72+
import apijson.orm.model.TestRecord;
6573

6674
/**config sql for JSON Request
6775
* @author Lemon
@@ -77,6 +85,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
7785
* 表名映射,隐藏真实表名,对安全要求很高的表可以这么做
7886
*/
7987
public static final Map<String, String> TABLE_KEY_MAP;
88+
public static final List<String> CONFIG_TABLE_LIST;
8089
public static final List<String> DATABASE_LIST;
8190
// 自定义where条件拼接
8291
public static final Map<String, String> RAW_MAP;
@@ -89,6 +98,16 @@ public abstract class AbstractSQLConfig implements SQLConfig {
8998
TABLE_KEY_MAP.put(SysTable.class.getSimpleName(), SysTable.TABLE_NAME);
9099
TABLE_KEY_MAP.put(SysColumn.class.getSimpleName(), SysColumn.TABLE_NAME);
91100
TABLE_KEY_MAP.put(ExtendedProperty.class.getSimpleName(), ExtendedProperty.TABLE_NAME);
101+
102+
CONFIG_TABLE_LIST = new ArrayList<>(); // Table, Column 等是系统表 AbstractVerifier.SYSTEM_ACCESS_MAP.keySet());
103+
CONFIG_TABLE_LIST.add(Function.class.getSimpleName());
104+
CONFIG_TABLE_LIST.add(Request.class.getSimpleName());
105+
CONFIG_TABLE_LIST.add(Response.class.getSimpleName());
106+
CONFIG_TABLE_LIST.add(Test.class.getSimpleName());
107+
CONFIG_TABLE_LIST.add(Access.class.getSimpleName());
108+
CONFIG_TABLE_LIST.add(Document.class.getSimpleName());
109+
CONFIG_TABLE_LIST.add(TestRecord.class.getSimpleName());
110+
92111

93112
DATABASE_LIST = new ArrayList<>();
94113
DATABASE_LIST.add(DATABASE_MYSQL);
@@ -1623,8 +1642,18 @@ public String getCompareString(String key, Object value, String type) throws Exc
16231642
}
16241643

16251644
public String getKey(String key) {
1645+
if (isTest()) {
1646+
if (key.contains("'")) { // || key.contains("#") || key.contains("--")) {
1647+
throw new IllegalArgumentException("参数 " + key + " 不合法!key 中不允许有单引号 ' !");
1648+
}
1649+
return getSQLValue(key).toString();
1650+
}
1651+
1652+
return getSQLKey(key);
1653+
}
1654+
public String getSQLKey(String key) {
16261655
String q = getQuote();
1627-
return (isKeyPrefix() ? getAliasWithQuote() + "." : "") + q + key + q;
1656+
return (isKeyPrefix() ? getAliasWithQuote() + "." : "") + q + key + q;
16281657
}
16291658

16301659
/**
@@ -1636,6 +1665,9 @@ private Object getValue(@NotNull Object value) {
16361665
preparedValueList.add(value);
16371666
return "?";
16381667
}
1668+
return getSQLValue(value);
1669+
}
1670+
public Object getSQLValue(@NotNull Object value) {
16391671
// return (value instanceof Number || value instanceof Boolean) && DATABASE_POSTGRESQL.equals(getDatabase()) ? value : "'" + value + "'";
16401672
return (value instanceof Number || value instanceof Boolean) ? value : "'" + value + "'"; //MySQL 隐式转换用不了索引
16411673
}
@@ -2230,9 +2262,15 @@ public static String getSQL(AbstractSQLConfig config) throws Exception {
22302262
case DELETE:
22312263
return "DELETE FROM " + tablePath + config.getWhereString(true);
22322264
default:
2265+
String explain = (config.isExplain() ? (config.isSQLServer() || config.isOracle() ? "SET STATISTICS PROFILE ON " : "EXPLAIN ") : "");
2266+
if (config.isTest() && RequestMethod.isGetMethod(config.getMethod(), true)) {
2267+
String q = config.getQuote(); // 生成 SELECT ( (24 >=0 AND 24 <3) ) AS `code` LIMIT 1 OFFSET 0
2268+
return explain + "SELECT " + config.getWhereString(false) + " AS " + q + JSONResponse.KEY_CODE + q + config.getLimitString();
2269+
}
2270+
22332271
config.setPreparedValueList(new ArrayList<Object>());
22342272
String column = config.getColumnString();
2235-
return (config.isExplain() ? (config.isSQLServer() || config.isOracle() ? "SET STATISTICS PROFILE ON " : "EXPLAIN ") : "") + "SELECT " + (config.getCache() == JSONRequest.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + getConditionString(column, tablePath, config);
2273+
return explain + "SELECT " + (config.getCache() == JSONRequest.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + getConditionString(column, tablePath, config);
22362274
}
22372275
}
22382276

@@ -2915,16 +2953,7 @@ else if (key.endsWith("-")) {//缩减,PUT查询时处理
29152953
}
29162954

29172955

2918-
public static interface Callback {
2919-
/**获取 SQLConfig 的实例
2920-
* @param method
2921-
* @param database
2922-
* @param schema
2923-
* @param table
2924-
* @return
2925-
*/
2926-
SQLConfig getSQLConfig(RequestMethod method, String database, String schema, String table);
2927-
2956+
public static interface IdCallback {
29282957
/**为 post 请求新建 id, 只能是 Long 或 String
29292958
* @param method
29302959
* @param database
@@ -2949,7 +2978,18 @@ public static interface Callback {
29492978
* @return
29502979
*/
29512980
String getUserIdKey(String database, String schema, String table);
2952-
2981+
}
2982+
2983+
public static interface Callback extends IdCallback {
2984+
/**获取 SQLConfig 的实例
2985+
* @param method
2986+
* @param database
2987+
* @param schema
2988+
* @param table
2989+
* @return
2990+
*/
2991+
SQLConfig getSQLConfig(RequestMethod method, String database, String schema, String table);
2992+
29532993
/**combine 里的 key 在 request 中 value 为 null 或不存在,即 request 中缺少用来作为 combine 条件的 key: value
29542994
* @param combine
29552995
* @param key

APIJSONORM/src/main/java/apijson/orm/Operation.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,26 @@
99
* @author Lemon
1010
*/
1111
public enum Operation {
12+
/**
13+
* 必须传的字段,结构是
14+
* "key0,key1,key2..."
15+
*/
16+
MUST,
17+
/**
18+
* @deprecated 用 MUST 代替,最早可能 4.5.0 移除
19+
*/
20+
NECESSARY,
1221

1322
/**
1423
* 不允许传的字段,结构是
1524
* "key0,key1,key2..."
16-
* TODO 改成 MUST 减少长度 ?
1725
*/
18-
DISALLOW,
19-
26+
REFUSE,
2027
/**
21-
* 必须传的字段,结构是
22-
* "key0,key1,key2..."
23-
* TODO 改成 REFUSE 减少长度 ?
28+
* @deprecated 用 REFUSE 代替,最早可能 4.5.0 移除
2429
*/
25-
NECESSARY,
26-
30+
DISALLOW,
31+
2732

2833
/**TODO 是否应该把数组类型写成 BOOLEANS, NUMBERS 等复数单词,以便抽取 enum ?扩展用 VERIFY 或 INSERT/UPDATE 远程函数等
2934
* 验证是否符合预设的类型:

0 commit comments

Comments
 (0)