query filter

This commit is contained in:
FangfangZhao 2018-10-21 22:24:04 +08:00
parent 6f9758731c
commit 7808b83b47
16 changed files with 236 additions and 155 deletions

View file

@ -152,8 +152,8 @@ public final class Application {
return getQueryFactory().createQuery(ajql);
}
public static Query createNoFilterQuery(String ajql) {
return getQueryFactory().createQueryUnfiltered(ajql);
public static Query createQueryNoFilter(String ajql) {
return getQueryFactory().createQueryNoFilter(ajql);
}
public static SQLExecutor getSQLExecutor() {

View file

@ -19,6 +19,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
package com.rebuild.server.bizz.privileges;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import cn.devezhao.bizz.security.member.BusinessUnit;
import cn.devezhao.persist4j.engine.ID;
@ -67,4 +70,18 @@ public class Department extends BusinessUnit {
}
return false;
}
/**
* 获取子部门包括所有子级
*
* @return
*/
public Set<BusinessUnit> getAllChildren() {
Set<BusinessUnit> children = new HashSet<>();
children.addAll(getChildren());
for (BusinessUnit child : getChildren()) {
children.addAll(((Department) child).getAllChildren());
}
return Collections.unmodifiableSet(children);
}
}

View file

@ -0,0 +1,143 @@
/*
rebuild - Building your system freely.
Copyright (C) 2018 devezhao <zhaofang123@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rebuild.server.bizz.privileges;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import com.rebuild.server.metadata.EntityHelper;
import com.rebuild.server.metadata.MetadataHelper;
import cn.devezhao.bizz.privileges.DepthEntry;
import cn.devezhao.bizz.privileges.Permission;
import cn.devezhao.bizz.privileges.Privileges;
import cn.devezhao.bizz.privileges.impl.BizzDepthEntry;
import cn.devezhao.bizz.privileges.impl.BizzPermission;
import cn.devezhao.bizz.security.QueryFilter;
import cn.devezhao.bizz.security.member.BusinessUnit;
import cn.devezhao.persist4j.Entity;
import cn.devezhao.persist4j.Filter;
/**
* 查询过滤器
*
* @author Zhao Fangfang
* @since 1.0, 2013-6-21
*/
public class EntityQueryFilter implements Filter, QueryFilter {
private static final long serialVersionUID = -7388577069739389698L;
/**
* 总是拒绝 */
public static final Filter DENIED = new EntityQueryFilter() {
private static final long serialVersionUID = -1841438304452108874L;
public String evaluate(Entity entity) {
return "( 1 = 0 )";
}
};
/**
* 总是允许 */
public static final Filter ALLOWED = new EntityQueryFilter() {
private static final long serialVersionUID = -1300184338130890817L;
public String evaluate(Entity entity) {
return "( 1 = 1 )";
}
};
private EntityQueryFilter() {
this.user = null;
this.specAction = null;
}
// --
final private User user;
final private Permission specAction;
protected EntityQueryFilter(User user) {
this(user, BizzPermission.READ);
}
protected EntityQueryFilter(User user, Permission specAction) {
this.user = user;
this.specAction = specAction;
}
@Override
public String evaluate(int entity) {
return evaluate(MetadataHelper.getEntity(entity));
}
@Override
public String evaluate(Entity entity) {
if (!EntityHelper.hasPrivilegesField(entity)) {
return DENIED.evaluate(null);
}
Privileges p = user.getOwningRole().getPrivileges(entity.getEntityCode());
if (p == BizzPermission.NONE) {
return DENIED.evaluate(null);
}
DepthEntry de = p.superlative(specAction);
if (de == BizzDepthEntry.GLOBAL) {
return ALLOWED.evaluate(null);
}
String fvFormat = "{0} = '{1}'";
if (de == BizzDepthEntry.PRIVATE) {
return appendViaShare(entity, MessageFormat.format(fvFormat, EntityHelper.owningUser, user.getIdentity()));
}
Department dept = user.getOwningDept();
String deptSql = MessageFormat.format(fvFormat, EntityHelper.owningDept, dept.getIdentity());
if (de == BizzDepthEntry.LOCAL) {
return appendViaShare(entity, deptSql);
}
if (de == BizzDepthEntry.DEEPDOWN) {
Set<String> sqls = new HashSet<>();
sqls.add(deptSql);
for (BusinessUnit child : dept.getAllChildren()) {
sqls.add(MessageFormat.format(fvFormat, EntityHelper.owningDept, child.getIdentity()));
}
return appendViaShare(entity, "(" + StringUtils.join(sqls, " or ") + ")");
}
return DENIED.evaluate(null);
}
/**
* TODO 通过共享添加的权限
*
* @param entity
* @param filter
* @return
*/
protected String appendViaShare(Entity entity, String filter) {
return filter;
}
}

View file

@ -1,98 +0,0 @@
/*
rebuild - Building your system freely.
Copyright (C) 2018 devezhao <zhaofang123@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rebuild.server.bizz.privileges;
import com.rebuild.server.metadata.EntityHelper;
import com.rebuild.server.metadata.MetadataHelper;
import cn.devezhao.bizz.security.EntityQueryFilter;
import cn.devezhao.persist4j.Entity;
import cn.devezhao.persist4j.Filter;
/**
* 查询过滤器
*
* @author Zhao Fangfang
* @since 1.0, 2013-6-21
*/
public class QueryFilter extends EntityQueryFilter implements Filter {
private static final long serialVersionUID = -7388577069739389698L;
/**
* 总是拒绝
*/
public static final QueryFilter DENIED = new QueryFilter() {
private static final long serialVersionUID = 13232323232L;
public String evaluate(int entity) {
return "( 1 = 0 )";
}
public String evaluate(Entity entity) {
return "( 1 = 0 )";
}
};
/**
* 总是允许
*/
public static final QueryFilter ALLOWED = new QueryFilter() {
private static final long serialVersionUID = 165789635786543L;
public String evaluate(int entity) {
return "( 1 = 1 )";
}
public String evaluate(Entity entity) {
return "( 1 = 1 )";
}
};
private QueryFilter() {
super(null, null);
}
// -----------------------------------------------------------------------------------
/**
* @param user
*/
public QueryFilter(User user) {
super(user);
}
/**
* @see #evaluate(int)
*/
public String evaluate(Entity entity) {
if (((User) user).isAdmin()) {
return ALLOWED.evaluate(entity);
} else if (!EntityHelper.hasPrivilegesField(entity)) {
return DENIED.evaluate(entity.getEntityCode());
}
return evaluate(entity.getEntityCode());
}
@Override
protected String evaluate(int entityCode, StringBuffer filtered) {
Entity entity = MetadataHelper.getEntity(entityCode);
if (((User) user).isAdmin()) {
return ALLOWED.evaluate(entity);
} else if (!EntityHelper.hasPrivilegesField(entity)) {
return DENIED.evaluate(entity.getEntityCode());
}
return super.evaluate(entityCode, filtered);
}
}

View file

@ -28,6 +28,7 @@ import cn.devezhao.bizz.privileges.Privileges;
import cn.devezhao.bizz.privileges.impl.BizzDepthEntry;
import cn.devezhao.bizz.privileges.impl.BizzPermission;
import cn.devezhao.bizz.security.member.Role;
import cn.devezhao.persist4j.Filter;
import cn.devezhao.persist4j.engine.ID;
/**
@ -324,16 +325,22 @@ public class SecurityManager {
* @param user
* @return
*/
public QueryFilter createQueryFilter(ID user) {
if (UserService.ADMIN_USER.equals(user)) {
return QueryFilter.ALLOWED;
}
public Filter createQueryFilter(ID user) {
return createQueryFilter(user, BizzPermission.READ);
}
/**
* 创建查询过滤器
*
* @param user
* @param action
* @return
*/
public Filter createQueryFilter(ID user, Permission action) {
User theUser = USER_STORE.getUser(user);
Role role = theUser.getOwningRole();
if (RoleService.ADMIN_ROLE.equals(role.getIdentity())) {
return QueryFilter.ALLOWED;
if (theUser.isAdmin()) {
return EntityQueryFilter.ALLOWED;
}
return new QueryFilter(theUser);
return new EntityQueryFilter(theUser, action);
}
}

View file

@ -228,7 +228,7 @@ public class UserStore {
oldDept.removeMember(oldUser);
}
Object[] u = Application.createNoFilterQuery(
Object[] u = Application.createQueryNoFilter(
"select " + USER_FS + " from User where userId = ?")
.setParameter(1, userId)
.unique();

View file

@ -63,7 +63,7 @@ public class Entity2Schema extends Field2Schema {
public String create(String entityLabel, String comments) {
String entityName = toPinyinString(entityLabel);
while (true) {
Object exists = Application.createNoFilterQuery(
Object exists = Application.createQueryNoFilter(
"select entityId from MetaEntity where entityName = ?")
.setParameter(1, entityName)
.unique();
@ -76,7 +76,7 @@ public class Entity2Schema extends Field2Schema {
String physicalName = "T__" + StringHelper.hyphenate(entityName).toUpperCase();
Object maxTypeCode[] = Application.createNoFilterQuery(
Object maxTypeCode[] = Application.createQueryNoFilter(
"select min(typeCode) from MetaEntity").unique();
int typeCode = maxTypeCode == null || ObjectUtils.toInt(maxTypeCode[0]) == 0
? 999 : (ObjectUtils.toInt(maxTypeCode[0]) - 1);

View file

@ -58,7 +58,7 @@ public class PickListService extends BaseService {
JSONArray showItem = config.getJSONArray("show");
JSONArray hideItem = config.getJSONArray("hide");
Object[][] itemsHold = Application.createNoFilterQuery(
Object[][] itemsHold = Application.createQueryNoFilter(
"select itemId from PickList where belongEntity = ? and belongField = ?")
.setParameter(1, field.getOwnEntity().getName())
.setParameter(2, field.getName())

View file

@ -68,11 +68,11 @@ public class LayoutManager {
String sql = "select layoutId,config,modifiedOn from LayoutConfig where belongEntity = '%s' and type = '%s' and applyTo = ?";
sql = String.format(sql, entity, type);
Object[] myself = Application.createNoFilterQuery(sql + " and createdBy = ?")
Object[] myself = Application.createQueryNoFilter(sql + " and createdBy = ?")
.setParameter(1, APPLY_SELF)
.setParameter(2, user)
.unique();
Object[] global = Application.createNoFilterQuery(sql).setParameter(1, APPLY_ALL).unique();
Object[] global = Application.createQueryNoFilter(sql).setParameter(1, APPLY_ALL).unique();
Object[] cfgs = global;
@ -115,7 +115,7 @@ public class LayoutManager {
sql = String.format(sql, APPLY_SELF, user.toLiteral());
}
Object[] detect = Application.createNoFilterQuery(sql).unique();
Object[] detect = Application.createQueryNoFilter(sql).unique();
return detect == null ? null : (ID) detect[0];
}

View file

@ -64,7 +64,7 @@ public class PickListManager {
* @return
*/
public static List<Map<String, Object>> getPickListRaw(String entity, String field, boolean isAll, boolean reload) {
Object[][] array = Application.createNoFilterQuery(
Object[][] array = Application.createQueryNoFilter(
"select itemId,text,isDefault,isHide from PickList where belongEntity = ? and belongField = ? order by seq asc")
.setParameter(1, entity)
.setParameter(2, field)

View file

@ -69,7 +69,7 @@ public class DynamicMetadataFactory extends ConfigurationMetadataFactory {
private void appendConfig4Db(Document config) {
final Element rootElement = config.getRootElement();
Object[][] customentity = Application.createNoFilterQuery(
Object[][] customentity = Application.createQueryNoFilter(
"select typeCode,entityName,physicalName,entityLabel,entityId,comments,icon,nameField from MetaEntity order by createdOn")
.array();
for (Object[] custom : customentity) {
@ -88,7 +88,7 @@ public class DynamicMetadataFactory extends ConfigurationMetadataFactory {
ENTITY_EXTMETA.put(name, new Object[] { custom[4], custom[5], custom[6] });
}
Object[][] customfield = Application.createNoFilterQuery(
Object[][] customfield = Application.createQueryNoFilter(
"select belongEntity,fieldName,physicalName,fieldLabel,displayType,nullable,creatable,updatable,precision,maxLength,defaultValue,refEntity,cascade,fieldId,comments,extConfig"
+ " from MetaField order by createdOn")
.array();

View file

@ -65,11 +65,11 @@ public class AdvFilterManager {
String sql = "select filterId,config,modifiedOn from FilterConfig where belongEntity = '%s' and filterName = '%s' and applyTo = ?";
sql = String.format(sql, entity, FILTER_QUICK);
Object[] myself = Application.createNoFilterQuery(sql + " and createdBy = ?")
Object[] myself = Application.createQueryNoFilter(sql + " and createdBy = ?")
.setParameter(1, LayoutManager.APPLY_SELF)
.setParameter(2, user)
.unique();
Object[] global = Application.createNoFilterQuery(sql).setParameter(1, LayoutManager.APPLY_ALL).unique();
Object[] global = Application.createQueryNoFilter(sql).setParameter(1, LayoutManager.APPLY_ALL).unique();
Object[] cfgs = global;
@ -133,7 +133,7 @@ public class AdvFilterManager {
sql = String.format(sql, LayoutManager.APPLY_SELF, user.toLiteral());
}
Object[] detect = Application.createNoFilterQuery(sql).unique();
Object[] detect = Application.createQueryNoFilter(sql).unique();
return detect == null ? null : (ID) detect[0];
}

View file

@ -18,8 +18,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
package com.rebuild.server.query;
import com.rebuild.server.Application;
import org.springframework.util.Assert;
import com.rebuild.server.Application;
import com.rebuild.server.bizz.privileges.EntityQueryFilter;
import cn.devezhao.persist4j.Filter;
import cn.devezhao.persist4j.PersistManagerFactory;
import cn.devezhao.persist4j.Query;
import cn.devezhao.persist4j.Record;
@ -34,14 +38,14 @@ import cn.devezhao.persist4j.query.NativeQuery;
*/
public class QueryFactory {
public static final int QUERY_TIMEOUT = 5 * 1000;
public static final int SLOW_LOGGER_TIME = 1 * 1000;
private static final int QUERY_TIMEOUT = 5 * 1000;
private static final int SLOW_LOGGER_TIME = 1 * 1000;
final private PersistManagerFactory PM_FACTORY;
final private PersistManagerFactory aPMFactory;
protected QueryFactory(PersistManagerFactory persistManagerFactory) {
protected QueryFactory(PersistManagerFactory aPMFactory) {
super();
this.PM_FACTORY = persistManagerFactory;
this.aPMFactory = aPMFactory;
}
/**
@ -58,30 +62,37 @@ public class QueryFactory {
* @return
*/
public Query createQuery(String ajql, ID user) {
Query query = PM_FACTORY.createQuery(ajql)
.setTimeout(QUERY_TIMEOUT)
.setSlowLoggerTime(SLOW_LOGGER_TIME)
.setFilter(Application.getSecurityManager().createQueryFilter(user));
return query;
return createQuery(ajql, Application.getSecurityManager().createQueryFilter(user));
}
/**
* @param ajql
* @return
*/
public Query createQueryUnfiltered(String ajql) {
Query query = PM_FACTORY.createQuery(ajql)
public Query createQueryNoFilter(String ajql) {
return createQuery(ajql, EntityQueryFilter.ALLOWED);
}
/**
* @param ajql
* @param user
* @return
*/
public Query createQuery(String ajql, Filter filter) {
Assert.notNull(filter, "'filter' not be null");
Query query = aPMFactory.createQuery(ajql)
.setTimeout(QUERY_TIMEOUT)
.setSlowLoggerTime(SLOW_LOGGER_TIME);
.setSlowLoggerTime(SLOW_LOGGER_TIME)
.setFilter(filter);
return query;
}
/**
* @param sql
* @return
*/
public NativeQuery createNativeQuery(String sql) {
return PM_FACTORY.createNativeQuery(sql)
return aPMFactory.createNativeQuery(sql)
.setTimeout(QUERY_TIMEOUT)
.setSlowLoggerTime(SLOW_LOGGER_TIME);
}

View file

@ -39,6 +39,7 @@ import cn.devezhao.bizz.privileges.Permission;
import cn.devezhao.bizz.privileges.impl.BizzPermission;
import cn.devezhao.persist4j.Entity;
import cn.devezhao.persist4j.Field;
import cn.devezhao.persist4j.Filter;
import cn.devezhao.persist4j.PersistManagerFactory;
import cn.devezhao.persist4j.Record;
import cn.devezhao.persist4j.engine.ID;
@ -71,19 +72,19 @@ public class GeneralEntityService extends BaseService {
/**
* 获取级联操作记录
*
* @param main 主记录
* @param cascades 级联实体
* @param recordOfMain 主记录
* @param cascadeEntities 级联实体
* @param action 动作
* @return
*/
public Map<String, Set<ID>> getCascadeRecords(ID main, String[] cascades, Permission action) {
if (cascades == null || cascades.length == 0) {
protected Map<String, Set<ID>> getCascadeRecords(ID recordOfMain, String[] cascadeEntities, Permission action) {
if (cascadeEntities == null || cascadeEntities.length == 0) {
return Collections.emptyMap();
}
Map<String, Set<ID>> cascadeRecordsMap = new HashMap<>();
Entity mainEntity = MetadataHelper.getEntity(main.getEntityCode());
for (String ref : cascades) {
Map<String, Set<ID>> entityRecordsMap = new HashMap<>();
Entity mainEntity = MetadataHelper.getEntity(recordOfMain.getEntityCode());
for (String ref : cascadeEntities) {
Entity refEntity = MetadataHelper.getEntity(ref);
String sql = "select %s from %s where ( ";
@ -91,21 +92,21 @@ public class GeneralEntityService extends BaseService {
Field[] refToFields = MetadataHelper.getReferenceToFields(mainEntity, refEntity);
for (Field refToField : refToFields) {
sql += refToField.getName() + " = '" + main + "' or ";
sql += refToField.getName() + " = '" + recordOfMain + "' or ";
}
sql = sql.substring(0, sql.length() - 4); // remove last ' or '
sql += " )";
// TODO 此处查询权限不对应该查询能分派的记录而非可读的记录
Filter filter = Application.getSecurityManager().createQueryFilter(Application.currentCallerUser(), action);
Object[][] array = Application.getQueryFactory().createQuery(sql, filter).array();
Object[][] array = Application.createQuery(sql).array();
Set<ID> records = new HashSet<>();
for (Object[] o : array) {
records.add((ID) o[0]);
}
cascadeRecordsMap.put(ref, records);
entityRecordsMap.put(ref, records);
}
return cascadeRecordsMap;
return entityRecordsMap;
}
@Override
@ -128,7 +129,7 @@ public class GeneralEntityService extends BaseService {
Map<String, Set<ID>> cass = getCascadeRecords(record, cascades, BizzPermission.DELETE);
for (Map.Entry<String, Set<ID>> e : cass.entrySet()) {
if (LOG.isDebugEnabled()) {
LOG.debug("级联删除 - " + e.getKey() + "/" + e.getValue().size());
LOG.debug("级联删除 - " + e.getKey() + " > " + e.getValue());
}
for (ID id : e.getValue()) {
affected += delete(id, null);
@ -164,7 +165,7 @@ public class GeneralEntityService extends BaseService {
Map<String, Set<ID>> cass = getCascadeRecords(record, cascades, BizzPermission.ASSIGN);
for (Map.Entry<String, Set<ID>> e : cass.entrySet()) {
if (LOG.isDebugEnabled()) {
LOG.debug("级联分派 - " + e.getKey() + "/" + e.getValue().size());
LOG.debug("级联分派 - " + e.getKey() + " > " + e.getValue());
}
for (ID id : e.getValue()) {
@ -207,7 +208,7 @@ public class GeneralEntityService extends BaseService {
Map<String, Set<ID>> cass = getCascadeRecords(record, cascades, BizzPermission.SHARE);
for (Map.Entry<String, Set<ID>> e : cass.entrySet()) {
if (LOG.isDebugEnabled()) {
LOG.debug("级联共享 - " + e.getKey() + "/" + e.getValue().size());
LOG.debug("级联共享 - " + e.getKey() + " > " + e.getValue());
}
for (ID id : e.getValue()) {

View file

@ -70,7 +70,7 @@ public class AdminEntryControll extends BaseControll {
ID adminId = getRequestUser(request);
String passwd = getParameterNotNull(request, "passwd");
Object[] foundUser = Application.createNoFilterQuery(
Object[] foundUser = Application.createQueryNoFilter(
"select password from User where userId = ?")
.setParameter(1, adminId)
.unique();

View file

@ -61,7 +61,7 @@ public class SignUpControll extends BaseControll {
return;
}
Object[] foundUser = Application.createNoFilterQuery(
Object[] foundUser = Application.createQueryNoFilter(
"select userId,password from User where loginName = ?")
.setParameter(1, user)
.unique();