在计算excludePath时逻辑错误

This commit is contained in:
Xu Chang 2023-07-12 13:56:29 +08:00
parent 8575186962
commit 409c93a181
2 changed files with 82 additions and 51 deletions

View File

@ -35,22 +35,25 @@ var RelationAuth = /** @class */ (function () {
var _a;
var anchors = [];
var anchorsOnMe = [];
for (var attr in filter) {
var _loop_1 = function (attr) {
// todo $or会发生什么by Xc
if (attr === '$and') {
filter[attr].forEach(function (ele) { return anchors.push.apply(anchors, tslib_1.__spreadArray([], tslib_1.__read(findHighestAnchors(entity, ele, path, excludePaths)), false)); });
continue;
return "continue";
}
var rel = (0, relation_1.judgeRelation)(_this.schema, entity, attr);
if (rel === 2) {
var path2 = path ? "".concat(path, ".").concat(attr) : attr;
anchors.push.apply(anchors, tslib_1.__spreadArray([], tslib_1.__read(findHighestAnchors(attr, filter[attr], path2, excludePaths)), false));
if (!excludePaths[path]) {
excludePaths[path] = [path2];
}
else if (!excludePaths[path].includes(path2)) {
excludePaths[path].push(path2);
}
var attributes = _this.schema[entity].attributes;
var ref = attributes.entity.ref;
(0, assert_1.default)(ref instanceof Array);
ref.forEach(function (refEntity) {
if (refEntity !== attr) {
var refEntityPath = path ? "".concat(path, ".").concat(refEntity) : refEntity;
excludePaths.push(refEntityPath);
}
});
}
else if (typeof rel === 'string') {
var path2 = path ? "".concat(path, ".").concat(attr) : attr;
@ -69,12 +72,15 @@ var RelationAuth = /** @class */ (function () {
relativePath: nextPath,
});
}
if (!excludePaths[path]) {
excludePaths[path] = [nextPath];
}
else if (!excludePaths[path].includes(nextPath)) {
excludePaths[path].push(nextPath);
}
var attributes = _this.schema[entity].attributes;
var ref = attributes.entity.ref;
(0, assert_1.default)(ref instanceof Array);
ref.forEach(function (refEntity) {
if (refEntity !== filter.entity) {
var refEntityPath = path ? "".concat(path, ".").concat(refEntity) : refEntity;
excludePaths.push(refEntityPath);
}
});
}
else if (((_a = _this.schema[entity].attributes[attr]) === null || _a === void 0 ? void 0 : _a.type) === 'ref') {
var ref = _this.schema[entity].attributes[attr].ref;
@ -90,6 +96,9 @@ var RelationAuth = /** @class */ (function () {
}
}
}
};
for (var attr in filter) {
_loop_1(attr);
}
if (anchors.length > 0) {
return anchors;
@ -114,7 +123,7 @@ var RelationAuth = /** @class */ (function () {
_this.relationalChecker[entity] = function (userId, actions, data, filter, userRelations) {
var filter2 = filter || data;
(0, assert_1.default)(filter2);
var excludePaths = {};
var excludePaths = [];
var anchors = findHighestAnchors(entity, filter2, '', excludePaths);
if (anchors.length === 0) {
throw new types_1.OakException('本次查询找不到锚定权限的入口,请确认查询条件合法');
@ -122,12 +131,23 @@ var RelationAuth = /** @class */ (function () {
anchors.sort(function (a1, a2) { return a2.relativePath.length - a1.relativePath.length; });
// 将这些找到的锚点和authCascadePaths进行锚定确认userRelation的搜索范围
var filters = authCascadePaths.filter(function (path) {
// 被entity的外键连接所排队的路径这个非常重要否则像extraFile这样的对象会有过多的查询路径
for (var k in excludePaths) {
if (path[1].startsWith(k) && !excludePaths[k].find(function (ele) { return path[1].startsWith("".concat(ele, ".")) || path[1] === ele; })) {
return false;
var e_1, _a;
try {
// 被entity的外键连接所排队的路径这个非常重要否则像extraFile这样的对象会有过多的查询路径
for (var excludePaths_1 = tslib_1.__values(excludePaths), excludePaths_1_1 = excludePaths_1.next(); !excludePaths_1_1.done; excludePaths_1_1 = excludePaths_1.next()) {
var excludePath = excludePaths_1_1.value;
if (path[1].startsWith(excludePath)) {
return false;
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (excludePaths_1_1 && !excludePaths_1_1.done && (_a = excludePaths_1.return)) _a.call(excludePaths_1);
}
finally { if (e_1) throw e_1.error; }
}
return true;
}).map(function (path) {
// 这里anchor的relativePath按长度倒排所以找到的第一个匹配关系应该就是最准确的
@ -436,7 +456,7 @@ var RelationAuth = /** @class */ (function () {
};
(0, assert_1.default)(!(data instanceof Array)); // createMulti这种情况实际中不会出现
var changeRoot = false;
var _loop_1 = function (attr) {
var _loop_2 = function (attr) {
var _a;
var rel = (0, relation_1.judgeRelation)(_this.schema, entity, attr);
if (rel === 2) {
@ -618,7 +638,7 @@ var RelationAuth = /** @class */ (function () {
}
};
for (var attr in data) {
_loop_1(attr);
_loop_2(attr);
}
return root;
};
@ -641,7 +661,7 @@ var RelationAuth = /** @class */ (function () {
this.checkActions(entity, operation, context);
};
RelationAuth.prototype.getDeducedCheckOperation = function (entity, operation) {
var e_1, _a;
var e_2, _a;
// 如果是deduce的对象将之转化为所deduce的对象上的权限检查
var deduceAttr = this.authDeduceRelationMap[entity];
(0, assert_1.default)(deduceAttr === 'entity', "\u5F53\u524D\u53EA\u652F\u6301entity\u4F5C\u4E3Adeduce\u5916\u952E\uFF0Centity\u662F\u300C".concat(entity, "\u300D"));
@ -673,12 +693,12 @@ var RelationAuth = /** @class */ (function () {
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
finally { if (e_2) throw e_2.error; }
}
}
else {
@ -941,9 +961,9 @@ var RelationAuth = /** @class */ (function () {
// 算法是先将整个update的根结点对象找到并找到为其赋权的relation再用此relation去查找所有子对象上的actionAuth
var result = [];
var _b = this.destructCascadeOperation(entity, operation), root = _b.root, children_1 = _b.children, userRelations = _b.userRelations;
var e_2 = root.entity, d = root.data, f = root.filter, a = root.action;
var e_3 = root.entity, d = root.data, f = root.filter, a = root.action;
if (userRelations.length > 0) {
(0, assert_1.default)(e_2 !== 'user');
(0, assert_1.default)(e_3 !== 'user');
(0, assert_1.default)(a === 'create' && !(d instanceof Array));
var createIds_1 = userRelations.map(function (ele) { return ele.relationId; });
// 这里处理的是创建对象时顺带创建相关权限要检查该权限是不是有create动作授权
@ -953,7 +973,7 @@ var RelationAuth = /** @class */ (function () {
relationId: 1,
},
filter: {
destEntity: e_2,
destEntity: e_3,
deActions: {
$contains: 'create',
},
@ -965,7 +985,7 @@ var RelationAuth = /** @class */ (function () {
var relationIds = aas2.map(function (ele) { return ele.relationId; });
var diff = (0, lodash_1.difference)(createIds_1, relationIds);
if (diff.length > 0) {
throw new types_1.OakUserUnpermittedException("\u60A8\u65E0\u6743\u521B\u5EFA\u300C".concat(e_2, "\u300D\u5BF9\u8C61\u4E0Aid\u4E3A\u300C").concat(diff.join(','), "\u300D\u7684\u7528\u6237\u6743\u9650"));
throw new types_1.OakUserUnpermittedException("\u60A8\u65E0\u6743\u521B\u5EFA\u300C".concat(e_3, "\u300D\u5BF9\u8C61\u4E0Aid\u4E3A\u300C").concat(diff.join(','), "\u300D\u7684\u7528\u6237\u6743\u9650"));
}
}));
}
@ -973,14 +993,14 @@ var RelationAuth = /** @class */ (function () {
var relationIds = aas.map(function (ele) { return ele.relationId; });
var diff = (0, lodash_1.difference)(createIds_1, relationIds);
if (diff.length > 0) {
throw new types_1.OakUserUnpermittedException("\u60A8\u65E0\u6743\u521B\u5EFA\u300C".concat(e_2, "\u300D\u5BF9\u8C61\u4E0Aid\u4E3A\u300C").concat(diff.join(','), "\u300D\u7684\u7528\u6237\u6743\u9650"));
throw new types_1.OakUserUnpermittedException("\u60A8\u65E0\u6743\u521B\u5EFA\u300C".concat(e_3, "\u300D\u5BF9\u8C61\u4E0Aid\u4E3A\u300C").concat(diff.join(','), "\u300D\u7684\u7528\u6237\u6743\u9650"));
}
}
}
if (['user', 'relation', 'oper', 'operEntity', 'modi', 'modiEntity', 'userRelation', 'actionAuth',
'freeActionAuth', 'relationAuth', 'userEntityGrant', 'relation'].includes(e_2)) {
'freeActionAuth', 'relationAuth', 'userEntityGrant', 'relation'].includes(e_3)) {
// 只要根对象能检查通过就算通过(暂定这个策略)
var r = this.checkSpecialEntity(e_2, {
var r = this.checkSpecialEntity(e_3, {
action: a,
data: d,
filter: f,
@ -990,7 +1010,7 @@ var RelationAuth = /** @class */ (function () {
}
}
else {
if (!this.relationalChecker[e_2]) {
if (!this.relationalChecker[e_3]) {
throw new types_1.OakUserUnpermittedException("".concat(root.entity, "\u4E0A\u4E0D\u5B58\u5728\u6709\u6548\u7684actionPath"));
}
var checker = this.relationalChecker[root.entity](userId, actions || [root.action], root.data, root.filter, userRelations);

View File

@ -70,7 +70,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
relativePath: string;
};
const findHighestAnchors = (entity: keyof ED, filter: NonNullable<ED[keyof ED]['Selection']['filter']>, path: string, excludePaths: Record<string, string[]>): Anchor[] => {
const findHighestAnchors = (entity: keyof ED, filter: NonNullable<ED[keyof ED]['Selection']['filter']>, path: string, excludePaths: string[]): Anchor[] => {
const anchors = [] as Anchor[];
const anchorsOnMe = [] as Anchor[];
for (const attr in filter) {
@ -85,12 +85,18 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
if (rel === 2) {
const path2 = path ? `${path}.${attr}` : attr;
anchors.push(...findHighestAnchors(attr, filter[attr], path2, excludePaths));
if (!excludePaths[path]) {
excludePaths[path] = [path2];
}
else if (!excludePaths[path].includes(path2)) {
excludePaths[path].push(path2);
}
const { attributes } = this.schema[entity];
const { ref } = attributes.entity;
assert(ref instanceof Array);
ref.forEach(
(refEntity) => {
if (refEntity !== attr) {
const refEntityPath = path ? `${path}.${refEntity}` : refEntity;
excludePaths.push(refEntityPath);
}
}
);
}
else if (typeof rel === 'string') {
const path2 = path ? `${path}.${attr}` : attr;
@ -109,12 +115,17 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
relativePath: nextPath,
});
}
if (!excludePaths[path]) {
excludePaths[path] = [nextPath];
}
else if (!excludePaths[path].includes(nextPath)) {
excludePaths[path].push(nextPath);
}
const { attributes } = this.schema[entity];
const { ref } = attributes.entity;
assert(ref instanceof Array);
ref.forEach(
(refEntity) => {
if (refEntity !== filter.entity) {
const refEntityPath = path ? `${path}.${refEntity}` : refEntity;
excludePaths.push(refEntityPath);
}
}
);
}
else if (this.schema[entity].attributes[attr as any]?.type === 'ref') {
const { ref } = this.schema[entity].attributes[attr as any];
@ -162,7 +173,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
) => {
const filter2 = filter || data as ED[keyof ED]['Selection']['filter'];
assert(filter2);
const excludePaths: Record<string, string[]> = {};
const excludePaths: string[] = [];
const anchors = findHighestAnchors(entity, filter2 as NonNullable<ED[keyof ED]['Selection']['filter']>, '', excludePaths);
if (anchors.length === 0) {
throw new OakException('本次查询找不到锚定权限的入口,请确认查询条件合法');
@ -175,8 +186,8 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
const filters = authCascadePaths.filter(
(path) => {
// 被entity的外键连接所排队的路径这个非常重要否则像extraFile这样的对象会有过多的查询路径
for (const k in excludePaths) {
if (path[1].startsWith(k) && !excludePaths[k].find(ele => path[1].startsWith(`${ele}.`) || path[1] === ele)) {
for (const excludePath of excludePaths) {
if (path[1].startsWith(excludePath)) {
return false;
}
}
@ -186,7 +197,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
(path) => {
// 这里anchor的relativePath按长度倒排所以找到的第一个匹配关系应该就是最准确的
const relatedAnchor = anchors.find(
(anchor) => path[1].startsWith(`${anchor.relativePath}.`)
(anchor) => path[1].startsWith(`${anchor.relativePath}.`)
|| path[1] === anchor.relativePath
|| !anchor.relativePath // relativePath如果是'', 所有的路径都成立
);
@ -725,7 +736,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
});
root = destructFn(rel, operationMto, '', parentFilter2);
}
else if (rel instanceof Array) {
else if (rel instanceof Array) {
const [entityOtm, foreignKey] = rel;
// 如果是一对多的deduceRelation可以忽略其父对象能过就行
if (!this.authDeduceRelationMap[entityOtm]) {
@ -1070,7 +1081,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
const { data } = operation as ED['user']['Update'];
if (data.hasOwnProperty('userRelation$user')) {
const { userRelation$user } = data;
const checkUrOperation = ( urOperation: ED['userRelation']['Operation']) => this.checkSpecialEntity('userRelation', urOperation, context);
const checkUrOperation = (urOperation: ED['userRelation']['Operation']) => this.checkSpecialEntity('userRelation', urOperation, context);
if (userRelation$user instanceof Array) {
const result = userRelation$user.map(ur => checkUrOperation(ur));
if (result[0] instanceof Promise) {