Skip to content

Commit 79f1778

Browse files
committed
Server:解决远程函数对比版本错误;解决批量新增可能被绕过权限和参数校验;删除已被废弃的 Operation
1 parent f87ebea commit 79f1778

File tree

8 files changed

+104
-94
lines changed

8 files changed

+104
-94
lines changed

APIJSON-Java-Server/APIJSONBoot/src/main/java/apijson/demo/server/DemoObjectParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
import zuo.biao.apijson.RequestMethod;
2525
import zuo.biao.apijson.StringUtil;
2626
import zuo.biao.apijson.server.AbstractObjectParser;
27+
import zuo.biao.apijson.server.AbstractParser;
2728
import zuo.biao.apijson.server.Join;
28-
import zuo.biao.apijson.server.Parser;
2929
import zuo.biao.apijson.server.SQLConfig;
3030

3131

@@ -59,7 +59,7 @@ public DemoObjectParser setMethod(RequestMethod method) {
5959
}
6060

6161
@Override
62-
public DemoObjectParser setParser(Parser<?> parser) {
62+
public DemoObjectParser setParser(AbstractParser<?> parser) {
6363
super.setParser(parser);
6464
return this;
6565
}

APIJSON-Java-Server/APIJSONORM/src/main/java/zuo/biao/apijson/JSONRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public JSONRequest setTag(String tag) {
6969
* @param version
7070
* @return
7171
*/
72-
public JSONRequest setVersion(String version) {
72+
public JSONRequest setVersion(Integer version) {
7373
return puts(KEY_VERSION, version);
7474
}
7575
/**set "format":format in outermost layer

APIJSON-Java-Server/APIJSONORM/src/main/java/zuo/biao/apijson/server/AbstractObjectParser.java

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static zuo.biao.apijson.RequestMethod.PUT;
2222
import static zuo.biao.apijson.server.SQLConfig.TYPE_ITEM;
2323

24+
import java.rmi.ServerException;
2425
import java.util.ArrayList;
2526
import java.util.Arrays;
2627
import java.util.HashMap;
@@ -36,6 +37,7 @@
3637
import com.alibaba.fastjson.JSONArray;
3738
import com.alibaba.fastjson.JSONObject;
3839

40+
import zuo.biao.apijson.JSONResponse;
3941
import zuo.biao.apijson.Log;
4042
import zuo.biao.apijson.NotNull;
4143
import zuo.biao.apijson.RequestMethod;
@@ -52,8 +54,8 @@ public abstract class AbstractObjectParser implements ObjectParser {
5254
private static final String TAG = "AbstractObjectParser";
5355

5456
@NotNull
55-
protected Parser<?> parser;
56-
public AbstractObjectParser setParser(Parser<?> parser) {
57+
protected AbstractParser<?> parser;
58+
public AbstractObjectParser setParser(AbstractParser<?> parser) {
5759
this.parser = parser;
5860
return this;
5961
}
@@ -233,43 +235,53 @@ public AbstractObjectParser parse() throws Exception {
233235
key = entry.getKey();
234236

235237
try {
236-
if (value instanceof JSONObject && key.startsWith("@") == false && key.endsWith("@") == false) {//JSONObject,往下一级提取
238+
if (value instanceof JSONObject && key.startsWith("@") == false && key.endsWith("@") == false) { //JSONObject,往下一级提取
237239
if (childMap != null) {//添加到childMap,最后再解析
238240
childMap.put(key, (JSONObject)value);
239241
}
240-
else {//直接解析并替换原来的,[]:{} 内必须直接解析,否则会因为丢掉count等属性,并且total@:"/[]/total"必须在[]:{} 后!
242+
else { //直接解析并替换原来的,[]:{} 内必须直接解析,否则会因为丢掉count等属性,并且total@:"/[]/total"必须在[]:{} 后!
241243
response.put(key, onChildParse(index, key, (JSONObject)value));
242244
index ++;
243245
}
244-
} else if (value instanceof JSONArray && method == POST &&
245-
key.startsWith("@") == false && key.endsWith("@") == false) {//JSONArray,批量新增,往下一级提取
246-
JSONArray valueArray = (JSONArray)value;
247-
248-
for (int i = 0; i < valueArray.size(); i++) {
249-
if (childMap != null) {//添加到childMap,最后再解析
250-
childMap.put(key, valueArray.getJSONObject(i));
251-
}
252-
else {//直接解析并替换原来的,[]:{} 内必须直接解析,否则会因为丢掉count等属性,并且total@:"/[]/total"必须在[]:{} 后!
253-
JSONObject result = (JSONObject)onChildParse(index, key, valueArray.getJSONObject(i));
254-
//合并结果
255-
JSONObject before = (JSONObject)response.get(key);
256-
if(result.get("code").equals(200)){
257-
if(before!=null){
258-
before.put("count",before.getInteger("count")+result.getInteger("count"));
259-
response.put(key, before);
260-
}else{
261-
response.put(key, result);
262-
}
263-
} else {
264-
//只要有一条失败,则抛出异常,全部失败
265-
throw new RuntimeException(key + "," + valueArray.getJSONObject(i) +",新增失败!");
266-
}
246+
}
247+
else if (method == PUT && value instanceof JSONArray
248+
&& (whereList == null || whereList.contains(key) == false)) { //PUT JSONArray
249+
onPUTArrayParse(key, (JSONArray) value);
250+
}
251+
else if (method == POST && value instanceof JSONArray && key.endsWith("[]") && JSONRequest.isTableKey(key.substring(0, key.length() - 2))) { //JSONArray,批量新增,往下一级提取
252+
String childKey = key.substring(0, key.length() - 2);
253+
JSONArray valueArray = (JSONArray) value;
254+
255+
int allCount = 0;
256+
JSONArray ids = new JSONArray();
257+
258+
int version = parser.getVersion();
259+
int maxUpdateCount = parser.getMaxUpdateCount();
260+
261+
for (int i = 0; i < valueArray.size(); i++) { //只要有一条失败,则抛出异常,全部失败
262+
//TODO 改成一条多 VALUES 的 SQL 性能更高,报错也更会更好处理,更人性化
263+
JSONRequest req = new JSONRequest(childKey, valueArray.getJSONObject(i));
264+
265+
//parser.getMaxSQLCount() ? 可能恶意调用接口,把数据库拖死
266+
JSONObject result = (JSONObject) onChildParse(0, "" + i, parser.parseCorrectRequest(method, childKey, version, "", req, maxUpdateCount, parser));
267+
result = result.getJSONObject(childKey);
268+
//
269+
boolean success = JSONResponse.isSuccess(result);
270+
int count = result == null ? null : result.getIntValue(JSONResponse.KEY_COUNT);
271+
272+
if (success == false || count != 1) { //如果 code = 200 但 count != 1,不能算成功,掩盖了错误为不好排查问题
273+
throw new ServerException("批量新增失败!" + key + "/" + i + ":" + (success ? "成功但 count != 1 !" : (result == null ? "null" : result.getString(JSONResponse.KEY_MSG))));
267274
}
275+
276+
allCount += count;
277+
ids.add(result.get(JSONResponse.KEY_ID));
268278
}
269-
index ++;
270-
} else if (method == PUT && value instanceof JSONArray
271-
&& (whereList == null || whereList.contains(key) == false)) {//PUT JSONArray
272-
onPUTArrayParse(key, (JSONArray) value);
279+
280+
JSONObject allResult = AbstractParser.newSuccessResult();
281+
allResult.put(JSONResponse.KEY_ID_IN, ids);
282+
allResult.put(JSONResponse.KEY_COUNT, allCount);
283+
284+
response.put(key, allResult); //不按原样返回,避免数据量过大
273285
}
274286
else {//JSONArray或其它Object,直接填充
275287
if (onParse(key, value) == false) {

APIJSON-Java-Server/APIJSONORM/src/main/java/zuo/biao/apijson/server/AbstractParser.java

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public AbstractParser<T> setMethod(RequestMethod method) {
120120
this.transactionIsolation = RequestMethod.isQueryMethod(method) ? Connection.TRANSACTION_NONE : Connection.TRANSACTION_REPEATABLE_READ;
121121
return this;
122122
}
123-
123+
124124
protected int version;
125125
@Override
126126
public int getVersion() {
@@ -131,7 +131,7 @@ public AbstractParser<T> setVersion(int version) {
131131
this.version = version;
132132
return this;
133133
}
134-
134+
135135
protected String tag;
136136
@Override
137137
public String getTag() {
@@ -462,8 +462,40 @@ public static JSONObject parseRequest(String request) throws Exception {
462462
}
463463

464464
@Override
465-
public JSONObject parseCorrectRequest(JSONObject target) throws Exception {
466-
return Structure.parseRequest(requestMethod, "", target, requestObject, getMaxUpdateCount(), this);
465+
public JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request
466+
, int maxUpdateCount, SQLCreator creator) throws Exception {
467+
468+
if (RequestMethod.isPublicMethod(method)) {
469+
return request;//需要指定JSON结构的get请求可以改为post请求。一般只有对安全性要求高的才会指定,而这种情况用明文的GET方式几乎肯定不安全
470+
}
471+
472+
if (StringUtil.isEmpty(tag, true)) {
473+
throw new IllegalArgumentException("请在最外层设置 tag !一般是 Table 名,例如 \"tag\": \"User\" ");
474+
}
475+
476+
//获取指定的JSON结构 <<<<<<<<<<<<
477+
JSONObject object = null;
478+
String error = "";
479+
try {
480+
object = getStructure("Request", JSONRequest.KEY_TAG, tag, version);
481+
} catch (Exception e) {
482+
error = e.getMessage();
483+
}
484+
if (object == null) {//empty表示随意操作 || object.isEmpty()) {
485+
throw new UnsupportedOperationException("非开放请求必须是后端 Request 表中校验规则允许的操作!\n " + error);
486+
}
487+
488+
JSONObject target = null;
489+
if (zuo.biao.apijson.JSONObject.isTableKey(tag) && object.containsKey(tag) == false) {//tag是table名
490+
target = new JSONObject(true);
491+
target.put(tag, object);
492+
} else {
493+
target = object;
494+
}
495+
//获取指定的JSON结构 >>>>>>>>>>>>>>
496+
497+
//JSONObject clone 浅拷贝没用,Structure.parse 会导致 structure 里面被清空,第二次从缓存里取到的就是 {}
498+
return Structure.parseRequest(method, name, target, request, maxUpdateCount, creator);
467499
}
468500

469501

@@ -585,41 +617,11 @@ else if (e instanceof NullPointerException) {
585617
*/
586618
@Override
587619
public JSONObject parseCorrectRequest() throws Exception {
588-
if (RequestMethod.isPublicMethod(requestMethod)) {
589-
return requestObject;//需要指定JSON结构的get请求可以改为post请求。一般只有对安全性要求高的才会指定,而这种情况用明文的GET方式几乎肯定不安全
590-
}
591-
592-
String tag = requestObject.getString(JSONRequest.KEY_TAG);
593-
if (StringUtil.isNotEmpty(tag, true) == false) {
594-
throw new IllegalArgumentException("请在最外层设置 tag !一般是 Table 名,例如 \"tag\": \"User\" ");
595-
}
596-
setTag(tag);
597-
598-
int version = requestObject.getIntValue(JSONRequest.KEY_VERSION);
599-
600-
JSONObject object = null;
601-
String error = "";
602-
try {
603-
object = getStructure("Request", JSONRequest.KEY_TAG, tag, version);
604-
} catch (Exception e) {
605-
error = e.getMessage();
606-
}
607-
if (object == null) {//empty表示随意操作 || object.isEmpty()) {
608-
throw new UnsupportedOperationException("非开放请求必须是后端 Request 表中校验规则允许的操作!\n " + error);
609-
}
610-
611-
JSONObject target = null;
612-
if (zuo.biao.apijson.JSONObject.isTableKey(tag) && object.containsKey(tag) == false) {//tag是table名
613-
target = new JSONObject(true);
614-
target.put(tag, object);
615-
} else {
616-
target = object;
617-
}
618-
//获取指定的JSON结构 >>>>>>>>>>>>>>
619-
620+
setTag(requestObject.getString(JSONRequest.KEY_TAG));
621+
setVersion(requestObject.getIntValue(JSONRequest.KEY_VERSION));
620622
requestObject.remove(JSONRequest.KEY_TAG);
621623
requestObject.remove(JSONRequest.KEY_VERSION);
622-
return parseCorrectRequest((JSONObject) target.clone());
624+
return parseCorrectRequest(requestMethod, tag, version, "", requestObject, getMaxUpdateCount(), this);
623625
}
624626

625627

APIJSON-Java-Server/APIJSONORM/src/main/java/zuo/biao/apijson/server/Operation.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,10 @@ public enum Operation {
4848
* 添加,当要被添加的对象不存在时
4949
*/
5050
INSERT,
51-
@Deprecated
52-
ADD, //用 INSERT 替代,和 RequestMethod.UPDATE 保持长度接近,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 PUT
5351
/**
5452
* 强行放入,不存在时就添加,存在时就修改
5553
*/
5654
UPDATE,
57-
@Deprecated
58-
PUT, //用 UPDATE 替代,容易和 RequestMethod.PUT 混淆,最快在 4.0.0 移除,请尽快修改 Request 表 structure 字段对应值里的 PUT
5955
/**
6056
* 替换,当要被替换的对象存在时
6157
*/

APIJSON-Java-Server/APIJSONORM/src/main/java/zuo/biao/apijson/server/Parser.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,9 @@ public interface Parser<T> {
9090

9191
JSONObject parseCorrectRequest() throws Exception;
9292

93-
JSONObject parseCorrectRequest(JSONObject target) throws Exception;
94-
93+
JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, String name, JSONObject request,
94+
int maxUpdateCount, SQLCreator creator) throws Exception;
95+
9596
JSONObject parseCorrectResponse(String table, JSONObject response) throws Exception;
9697

9798
JSONObject getStructure(String table, String key, String value, int version) throws Exception;
@@ -153,4 +154,5 @@ public interface Parser<T> {
153154
void rollback(Savepoint savepoint) throws SQLException;
154155
void commit() throws SQLException;
155156
void close();
157+
156158
}

APIJSON-Java-Server/APIJSONORM/src/main/java/zuo/biao/apijson/server/RemoteFunction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public static Object invoke(@NotNull RemoteFunction fun, @NotNull JSONObject req
7777
}
7878

7979
int v = row.getIntValue("version");
80-
if (v < fun.getVersion()) {
80+
if (fun.getVersion() < v) {
8181
throw new UnsupportedOperationException("不允许 version = " + fun.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + v + " !");
8282
}
8383
String t = row.getString("tag");

APIJSON-Java-Server/APIJSONORM/src/main/java/zuo/biao/apijson/server/Structure.java

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616

1717
import static zuo.biao.apijson.JSONObject.KEY_ID;
1818
import static zuo.biao.apijson.JSONObject.KEY_USER_ID;
19-
import static zuo.biao.apijson.server.Operation.ADD;
2019
import static zuo.biao.apijson.server.Operation.DISALLOW;
2120
import static zuo.biao.apijson.server.Operation.INSERT;
2221
import static zuo.biao.apijson.server.Operation.NECESSARY;
23-
import static zuo.biao.apijson.server.Operation.PUT;
2422
import static zuo.biao.apijson.server.Operation.REMOVE;
2523
import static zuo.biao.apijson.server.Operation.REPLACE;
2624
import static zuo.biao.apijson.server.Operation.TYPE;
@@ -230,30 +228,24 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
230228
JSONObject type = target.getJSONObject(TYPE.name());
231229
JSONObject verify = target.getJSONObject(VERIFY.name());
232230
JSONObject insert = target.getJSONObject(INSERT.name());
233-
JSONObject add = target.getJSONObject(ADD.name());
234231
JSONObject update = target.getJSONObject(UPDATE.name());
235-
JSONObject put = target.getJSONObject(PUT.name());
236232
JSONObject replace = target.getJSONObject(REPLACE.name());
237233

238234
String unique = StringUtil.getNoBlankString(target.getString(UNIQUE.name()));
239235
String remove = StringUtil.getNoBlankString(target.getString(REMOVE.name()));
240236
String necessary = StringUtil.getNoBlankString(target.getString(NECESSARY.name()));
241237
String disallow = StringUtil.getNoBlankString(target.getString(DISALLOW.name()));
242238

243-
//不还原,传进来的target不应该是原来的
244239
target.remove(TYPE.name());
245240
target.remove(VERIFY.name());
246241
target.remove(INSERT.name());
247-
target.remove(ADD.name());
248242
target.remove(UPDATE.name());
249-
target.remove(PUT.name());
250243
target.remove(REPLACE.name());
251244

252245
target.remove(UNIQUE.name());
253246
target.remove(REMOVE.name());
254247
target.remove(NECESSARY.name());
255248
target.remove(DISALLOW.name());
256-
//获取配置>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
257249

258250

259251

@@ -373,9 +365,7 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
373365
real = operate(TYPE, type, real, creator);
374366
real = operate(VERIFY, verify, real, creator);
375367
real = operate(INSERT, insert, real, creator);
376-
real = operate(ADD, add, real, creator);
377368
real = operate(UPDATE, update, real, creator);
378-
real = operate(PUT, put, real, creator);
379369
real = operate(REPLACE, replace, real, creator);
380370
//校验与修改Request>>>>>>>>>>>>>>>>>
381371

@@ -390,6 +380,20 @@ public static JSONObject parse(String name, JSONObject target, JSONObject real
390380
}
391381
//校验重复>>>>>>>>>>>>>>>>>>>
392382

383+
384+
//还原 <<<<<<<<<<
385+
target.put(TYPE.name(), type);
386+
target.put(VERIFY.name(), verify);
387+
target.put(INSERT.name(), insert);
388+
target.put(UPDATE.name(), update);
389+
target.put(REPLACE.name(), replace);
390+
391+
target.put(UNIQUE.name(), unique);
392+
target.put(REMOVE.name(), remove);
393+
target.put(NECESSARY.name(), necessary);
394+
target.put(DISALLOW.name(), disallow);
395+
//还原 >>>>>>>>>>
396+
393397
Log.i(TAG, "parse return real = " + JSON.toJSONString(real));
394398
return real;
395399
}
@@ -433,9 +437,6 @@ else if (opt == VERIFY) {
433437
else if (opt == UPDATE) {
434438
real.put(tk, tv);
435439
}
436-
else if (opt == PUT) {
437-
real.put(tk, tv);
438-
}
439440
else {
440441
if (real.containsKey(tk)) {
441442
if (opt == REPLACE) {
@@ -446,9 +447,6 @@ else if (opt == PUT) {
446447
if (opt == INSERT) {
447448
real.put(tk, tv);
448449
}
449-
if (opt == ADD) {
450-
real.put(tk, tv);
451-
}
452450
}
453451
}
454452
}

0 commit comments

Comments
 (0)