mirror of
https://github.com/hs-web/hsweb-framework.git
synced 2026-06-04 11:52:41 +08:00
优化权限控制,增加测试用例
This commit is contained in:
@@ -7,20 +7,26 @@ import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.authorization.define.AuthorizingContext;
|
||||
import org.hswebframework.web.authorization.basic.handler.AuthorizingHandler;
|
||||
import org.hswebframework.web.authorization.define.AuthorizeDefinition;
|
||||
import org.hswebframework.web.authorization.define.Phased;
|
||||
import org.hswebframework.web.authorization.exception.UnAuthorizedException;
|
||||
import org.hswebframework.web.boost.aop.context.MethodInterceptorHolder;
|
||||
import org.hswebframework.web.boost.aop.context.MethodInterceptorContext;
|
||||
import org.hswebframework.web.controller.message.ResponseMessage;
|
||||
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor {
|
||||
|
||||
private static final long serialVersionUID = 1154190623020670672L;
|
||||
|
||||
public AopAuthorizingController(AuthorizingHandler authorizingHandler, AopMethodAuthorizeDefinitionParser aopMethodAuthorizeDefinitionParser) {
|
||||
super((MethodInterceptor) methodInvocation -> {
|
||||
|
||||
@@ -29,22 +35,36 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor
|
||||
MethodInterceptorContext paramContext = holder.createParamContext();
|
||||
|
||||
AuthorizeDefinition definition = aopMethodAuthorizeDefinitionParser.parse(paramContext);
|
||||
|
||||
Object result = true;
|
||||
boolean isControl = false;
|
||||
if (null != definition) {
|
||||
Authentication authentication = Authentication.current().orElseThrow(UnAuthorizedException::new);
|
||||
|
||||
if (!definition.isEmpty()) {
|
||||
AuthorizingContext context = new AuthorizingContext();
|
||||
context.setAuthentication(authentication);
|
||||
context.setDefinition(definition);
|
||||
context.setParamContext(paramContext);
|
||||
authorizingHandler.handle(context);
|
||||
isControl = true;
|
||||
if (definition.getPhased() == Phased.before) {
|
||||
authorizingHandler.handle(context);
|
||||
result = methodInvocation.proceed();
|
||||
} else {
|
||||
result = methodInvocation.proceed();
|
||||
context.setParamContext(holder.createParamContext(result));
|
||||
authorizingHandler.handle(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodInvocation.proceed();
|
||||
if (!isControl) {
|
||||
result = methodInvocation.proceed();
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> aClass) {
|
||||
//对controller进行控制
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.hswebframework.web.authorization.basic.define;
|
||||
|
||||
import lombok.*;
|
||||
import org.hswebframework.web.authorization.access.DataAccessController;
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.authorization.annotation.Logical;
|
||||
@@ -7,6 +8,7 @@ import org.hswebframework.web.authorization.annotation.RequiresDataAccess;
|
||||
import org.hswebframework.web.authorization.annotation.RequiresExpression;
|
||||
import org.hswebframework.web.authorization.define.AuthorizeDefinition;
|
||||
import org.hswebframework.web.authorization.define.DataAccessDefinition;
|
||||
import org.hswebframework.web.authorization.define.Phased;
|
||||
import org.hswebframework.web.authorization.define.Script;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -19,6 +21,10 @@ import java.util.Set;
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DefaultBasicAuthorizeDefinition implements AuthorizeDefinition {
|
||||
private boolean dataAccessControl;
|
||||
|
||||
@@ -38,97 +44,23 @@ public class DefaultBasicAuthorizeDefinition implements AuthorizeDefinition {
|
||||
|
||||
private DataAccessDefinition dataAccessDefinition;
|
||||
|
||||
private Phased phased = Phased.before;
|
||||
|
||||
@Override
|
||||
public Phased getPhased() {
|
||||
return phased;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataAccessControl() {
|
||||
return dataAccessControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPermissions() {
|
||||
return new HashSet<>(permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActions() {
|
||||
return new HashSet<>(actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return new HashSet<>(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getUser() {
|
||||
return new HashSet<>(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Script getScript() {
|
||||
return script;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logical getLogical() {
|
||||
return logical;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return permissions.isEmpty() && roles.isEmpty() && user.isEmpty() && script == null && dataAccessDefinition == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataAccessDefinition getDataAccessDefinition() {
|
||||
return dataAccessDefinition;
|
||||
}
|
||||
|
||||
public void setDataAccessDefinition(DataAccessDefinition dataAccessDefinition) {
|
||||
this.dataAccessDefinition = dataAccessDefinition;
|
||||
}
|
||||
|
||||
public void setActions(Set<String> actions) {
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
public void setDataAccessControl(boolean dataAccessControl) {
|
||||
this.dataAccessControl = dataAccessControl;
|
||||
}
|
||||
|
||||
public void setLogical(Logical logical) {
|
||||
this.logical = logical;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void setPermissions(Set<String> permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
public void setRoles(Set<String> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public void setScript(Script script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public void setUser(Set<String> user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public void put(Authorize authorize) {
|
||||
if (null == authorize || authorize.ignore()) {
|
||||
return;
|
||||
@@ -141,6 +73,7 @@ public class DefaultBasicAuthorizeDefinition implements AuthorizeDefinition {
|
||||
logical = authorize.logical();
|
||||
}
|
||||
message = authorize.message();
|
||||
phased=authorize.phased();
|
||||
}
|
||||
|
||||
public void put(RequiresExpression expression) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.hswebframework.web.authorization.basic.define;
|
||||
import org.hswebframework.web.authorization.annotation.Logical;
|
||||
import org.hswebframework.web.authorization.define.AuthorizeDefinition;
|
||||
import org.hswebframework.web.authorization.define.DataAccessDefinition;
|
||||
import org.hswebframework.web.authorization.define.Phased;
|
||||
import org.hswebframework.web.authorization.define.Script;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -17,6 +18,11 @@ public class EmptyAuthorizeDefinition implements AuthorizeDefinition {
|
||||
private EmptyAuthorizeDefinition() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Phased getPhased() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
@@ -52,7 +52,6 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler {
|
||||
|
||||
//表达式权限控制
|
||||
handleExpression(context.getAuthentication(), context.getDefinition(), context.getParamContext());
|
||||
|
||||
}
|
||||
|
||||
protected void handleDataAccess(AuthorizingContext context) {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.hswebframework.web.authorization.basic.handler;
|
||||
|
||||
public interface MethodProceedCallback {
|
||||
void call(Object result);
|
||||
}
|
||||
@@ -30,11 +30,11 @@ public final class DefaultDataAccessController implements DataAccessController {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
this.parent = parent;
|
||||
addHandler(new CustomDataAccessHandler());
|
||||
addHandler(new OwnCreatedDataAccessHandler());
|
||||
addHandler(new ScriptDataAccessHandler());
|
||||
addHandler(new FieldFilterDataAccessHandler());
|
||||
addHandler(new FieldScopeDataAccessHandler());
|
||||
addHandler(new CustomDataAccessHandler()).
|
||||
addHandler(new OwnCreatedDataAccessHandler()).
|
||||
addHandler(new ScriptDataAccessHandler()).
|
||||
addHandler(new FieldFilterDataAccessHandler()).
|
||||
addHandler(new FieldScopeDataAccessHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,7 +43,6 @@ public final class DefaultDataAccessController implements DataAccessController {
|
||||
parent.doAccess(access, context);
|
||||
}
|
||||
return handlers.stream()
|
||||
// TODO: 17-3-28 可以换成access对应的handler以提高效率
|
||||
.filter(handler -> handler.isSupport(access))
|
||||
.allMatch(handler -> handler.handle(access, context));
|
||||
}
|
||||
|
||||
@@ -6,13 +6,19 @@ import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
import org.hswebframework.web.authorization.access.DataAccessHandler;
|
||||
import org.hswebframework.web.authorization.access.FieldFilterDataAccessConfig;
|
||||
import org.hswebframework.web.authorization.define.AuthorizingContext;
|
||||
import org.hswebframework.web.authorization.define.Phased;
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
import org.hswebframework.web.commons.entity.param.QueryParamEntity;
|
||||
import org.hswebframework.web.commons.model.Model;
|
||||
import org.hswebframework.web.controller.message.ResponseMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 数据权限字段过滤处理,目前仅支持deny. {@link DataAccessConfig.DefaultType#DENY_FIELDS}
|
||||
@@ -33,6 +39,7 @@ public class FieldFilterDataAccessHandler implements DataAccessHandler {
|
||||
|
||||
switch (access.getAction()) {
|
||||
case Permission.ACTION_QUERY:
|
||||
case Permission.ACTION_GET:
|
||||
return doQueryAccess(filterDataAccessConfig, context);
|
||||
case Permission.ACTION_UPDATE:
|
||||
return doUpdateAccess(filterDataAccessConfig, context);
|
||||
@@ -53,7 +60,7 @@ public class FieldFilterDataAccessHandler implements DataAccessHandler {
|
||||
*/
|
||||
protected boolean doUpdateAccess(FieldFilterDataAccessConfig accesses, AuthorizingContext params) {
|
||||
Object supportParam = params.getParamContext().getParams().values().stream()
|
||||
.filter(param -> (param instanceof Entity) || (param instanceof Model)||(param instanceof Map))
|
||||
.filter(param -> (param instanceof Entity) || (param instanceof Model) || (param instanceof Map))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
if (null != supportParam) {
|
||||
@@ -73,18 +80,40 @@ public class FieldFilterDataAccessHandler implements DataAccessHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
protected boolean doQueryAccess(FieldFilterDataAccessConfig access, AuthorizingContext context) {
|
||||
QueryParamEntity entity = context.getParamContext().getParams()
|
||||
.values().stream()
|
||||
.filter(QueryParamEntity.class::isInstance)
|
||||
.map(QueryParamEntity.class::cast)
|
||||
.findAny().orElse(null);
|
||||
if (entity == null) {
|
||||
logger.warn("try validate query access, but query entity is null or not instance of org.hswebframework.web.commons.entity.Entity");
|
||||
return true;
|
||||
if (context.getDefinition().getPhased() == Phased.before) {
|
||||
QueryParamEntity entity = context.getParamContext().getParams()
|
||||
.values().stream()
|
||||
.filter(QueryParamEntity.class::isInstance)
|
||||
.map(QueryParamEntity.class::cast)
|
||||
.findAny().orElse(null);
|
||||
if (entity == null) {
|
||||
logger.warn("try validate query access, but query entity is null or not instance of org.hswebframework.web.commons.entity.Entity");
|
||||
return true;
|
||||
}
|
||||
entity.excludes(access.getFields().toArray(new String[access.getFields().size()]));
|
||||
} else {
|
||||
Object result = InvokeResultUtils.convertRealResult(context.getParamContext().getInvokeResult());
|
||||
if (result instanceof Collection) {
|
||||
((Collection) result).forEach(o -> setObjectPropertyNull(o, access.getFields()));
|
||||
} else {
|
||||
setObjectPropertyNull(result, access.getFields());
|
||||
}
|
||||
}
|
||||
entity.excludes(access.getFields().toArray(new String[access.getFields().size()]));
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void setObjectPropertyNull(Object obj, Set<String> fields) {
|
||||
if (null == obj) {
|
||||
return;
|
||||
}
|
||||
for (String field : fields) {
|
||||
try {
|
||||
BeanUtilsBean.getInstance().getPropertyUtils().setProperty(obj, field, null);
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,18 @@ import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
import org.hswebframework.web.authorization.access.DataAccessHandler;
|
||||
import org.hswebframework.web.authorization.access.FieldScopeDataAccessConfig;
|
||||
import org.hswebframework.web.authorization.define.AuthorizingContext;
|
||||
import org.hswebframework.web.authorization.define.Phased;
|
||||
import org.hswebframework.web.commons.entity.param.QueryParamEntity;
|
||||
import org.hswebframework.web.controller.QueryController;
|
||||
import org.hswebframework.web.service.QueryService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
@@ -38,8 +42,8 @@ public class FieldScopeDataAccessHandler implements DataAccessHandler {
|
||||
if (controller != null) {
|
||||
switch (access.getAction()) {
|
||||
case Permission.ACTION_QUERY:
|
||||
return doQueryAccess(own, context);
|
||||
case Permission.ACTION_GET:
|
||||
return doQueryAccess(own, context);
|
||||
case Permission.ACTION_DELETE:
|
||||
case Permission.ACTION_UPDATE:
|
||||
return doRWAccess(own, context, controller);
|
||||
@@ -78,29 +82,58 @@ public class FieldScopeDataAccessHandler implements DataAccessHandler {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
protected boolean doQueryAccess(FieldScopeDataAccessConfig access, AuthorizingContext context) {
|
||||
QueryParamEntity entity = context.getParamContext().getParams()
|
||||
.values().stream()
|
||||
.filter(QueryParamEntity.class::isInstance)
|
||||
.map(QueryParamEntity.class::cast)
|
||||
.findAny().orElse(null);
|
||||
if (entity == null) {
|
||||
logger.warn("try validate query access, but query entity is null or not instance of org.hswebframework.web.commons.entity.Entity");
|
||||
return true;
|
||||
if (context.getDefinition().getPhased() == Phased.before) {
|
||||
QueryParamEntity entity = context.getParamContext().getParams()
|
||||
.values().stream()
|
||||
.filter(QueryParamEntity.class::isInstance)
|
||||
.map(QueryParamEntity.class::cast)
|
||||
.findAny().orElse(null);
|
||||
if (entity == null) {
|
||||
logger.warn("try validate query access, but query entity is null or not instance of org.hswebframework.web.commons.entity.Entity");
|
||||
return true;
|
||||
}
|
||||
//重构查询条件
|
||||
//如: 旧的条件为 where column =? or column = ?
|
||||
//重构后为: where creatorId=? and (column = ? or column = ?)
|
||||
List<Term> oldParam = entity.getTerms();
|
||||
//清空旧的查询条件
|
||||
entity.setTerms(new ArrayList<>());
|
||||
//添加一个查询条件
|
||||
entity.addTerm(createQueryTerm(access))
|
||||
//客户端提交的参数 作为嵌套参数
|
||||
.nest().setTerms(oldParam);
|
||||
} else {
|
||||
Object result = InvokeResultUtils.convertRealResult(context.getParamContext().getInvokeResult());
|
||||
if (result == null) {
|
||||
return true;
|
||||
}
|
||||
if (result instanceof Collection) {
|
||||
return ((Collection) result).stream().allMatch(obj -> propertyInScope(obj, access.getField(), access.getScope()));
|
||||
} else {
|
||||
return propertyInScope(result, access.getField(), access.getScope());
|
||||
}
|
||||
}
|
||||
//重构查询条件
|
||||
//如: 旧的条件为 where column =? or column = ?
|
||||
//重构后为: where creatorId=? and (column = ? or column = ?)
|
||||
List<Term> oldParam = entity.getTerms();
|
||||
//清空旧的查询条件
|
||||
entity.setTerms(new ArrayList<>());
|
||||
//添加一个查询条件
|
||||
entity.addTerm(createQueryTerm(access))
|
||||
//客户端提交的参数 作为嵌套参数
|
||||
.nest().setTerms(oldParam);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean propertyInScope(Object obj, String property, Set<Object> scope) {
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Object value = BeanUtilsBean.getInstance().getProperty(obj, property);
|
||||
if (null != value) {
|
||||
return scope.contains(value);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
logger.warn("can not get property {} from {},{}", property, obj, ignore.getMessage());
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
protected Term createQueryTerm(FieldScopeDataAccessConfig access) {
|
||||
Term term = new Term();
|
||||
term.setType(Term.Type.and);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.hswebframework.web.authorization.basic.handler.access;
|
||||
|
||||
import org.hswebframework.web.controller.message.ResponseMessage;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public class InvokeResultUtils {
|
||||
public static Object convertRealResult(Object result) {
|
||||
if (result instanceof ResponseMessage) {
|
||||
return ((ResponseMessage) result).getResult();
|
||||
}
|
||||
if (result instanceof ResponseEntity) {
|
||||
return ((ResponseEntity) result).getBody();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.hswebframework.web.authorization.basic.handler.access;
|
||||
|
||||
import org.apache.commons.beanutils.PropertyUtils;
|
||||
import org.apache.commons.beanutils.PropertyUtilsBean;
|
||||
import org.hswebframework.ezorm.core.param.Term;
|
||||
import org.hswebframework.utils.ClassUtils;
|
||||
import org.hswebframework.web.authorization.Permission;
|
||||
@@ -7,6 +9,7 @@ import org.hswebframework.web.authorization.access.DataAccessConfig;
|
||||
import org.hswebframework.web.authorization.access.DataAccessHandler;
|
||||
import org.hswebframework.web.authorization.access.OwnCreatedDataAccessConfig;
|
||||
import org.hswebframework.web.authorization.define.AuthorizingContext;
|
||||
import org.hswebframework.web.authorization.define.Phased;
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
import org.hswebframework.web.commons.entity.RecordCreationEntity;
|
||||
import org.hswebframework.web.commons.entity.param.QueryParamEntity;
|
||||
@@ -15,12 +18,14 @@ import org.hswebframework.web.service.QueryService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* TODO 完成注释
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class OwnCreatedDataAccessHandler implements DataAccessHandler {
|
||||
@@ -37,12 +42,13 @@ public class OwnCreatedDataAccessHandler implements DataAccessHandler {
|
||||
Object controller = context.getParamContext().getTarget();
|
||||
if (controller != null) {
|
||||
switch (access.getAction()) {
|
||||
case Permission.ACTION_GET:
|
||||
case Permission.ACTION_QUERY:
|
||||
return doQueryAccess(own, context);
|
||||
case Permission.ACTION_GET:
|
||||
|
||||
case Permission.ACTION_DELETE:
|
||||
case Permission.ACTION_UPDATE:
|
||||
return doRWAccess(own, context,controller);
|
||||
return doRWAccess(own, context, controller);
|
||||
case Permission.ACTION_ADD:
|
||||
//put creator_id to result
|
||||
return putCreatorId(own, context);
|
||||
@@ -91,32 +97,60 @@ public class OwnCreatedDataAccessHandler implements DataAccessHandler {
|
||||
}
|
||||
|
||||
protected boolean doQueryAccess(OwnCreatedDataAccessConfig access, AuthorizingContext context) {
|
||||
Entity entity = context.getParamContext().getParams()
|
||||
.values().stream()
|
||||
.filter(Entity.class::isInstance)
|
||||
.map(Entity.class::cast)
|
||||
.findAny().orElse(null);
|
||||
if (entity == null) {
|
||||
logger.warn("try validate query access, but query entity is null or not instance of org.hswebframework.web.commons.entity.Entity");
|
||||
String userId = context.getAuthentication().getUser().getId();
|
||||
|
||||
if (context.getDefinition().getPhased() == Phased.before) {
|
||||
Entity entity = context.getParamContext().getParams()
|
||||
.values().stream()
|
||||
.filter(Entity.class::isInstance)
|
||||
.map(Entity.class::cast)
|
||||
.findAny().orElse(null);
|
||||
if (entity == null) {
|
||||
logger.warn("try validate query access, but query entity is null or not instance of org.hswebframework.web.commons.entity.Entity");
|
||||
return true;
|
||||
}
|
||||
if (entity instanceof QueryParamEntity) {
|
||||
QueryParamEntity queryParamEntity = ((QueryParamEntity) entity);
|
||||
//重构查询条件
|
||||
//如: 旧的条件为 where name =? or name = ?
|
||||
//重构后为: where creatorId=? and (name = ? or name = ?)
|
||||
List<Term> oldParam = queryParamEntity.getTerms();
|
||||
//清空旧的查询条件
|
||||
queryParamEntity.setTerms(new ArrayList<>());
|
||||
//添加一个查询条件
|
||||
queryParamEntity
|
||||
.where(RecordCreationEntity.creatorId, userId)
|
||||
//客户端提交的参数 作为嵌套参数
|
||||
.nest().setTerms(oldParam);
|
||||
} else if (entity instanceof RecordCreationEntity) {
|
||||
((RecordCreationEntity) entity).setCreatorId(userId);
|
||||
} else {
|
||||
logger.warn("try validate query access,but entity not support, QueryParamEntity and RecordCreationEntity support now!");
|
||||
}
|
||||
} else {
|
||||
Object result = InvokeResultUtils.convertRealResult(context.getParamContext().getInvokeResult());
|
||||
return matchCreatorId(result, userId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
protected boolean matchCreatorId(Object result, String userId) {
|
||||
if (null == result) {
|
||||
return true;
|
||||
}
|
||||
if (entity instanceof QueryParamEntity) {
|
||||
QueryParamEntity queryParamEntity = ((QueryParamEntity) entity);
|
||||
//重构查询条件
|
||||
//如: 旧的条件为 where name =? or name = ?
|
||||
//重构后为: where creatorId=? and (name = ? or name = ?)
|
||||
List<Term> oldParam = queryParamEntity.getTerms();
|
||||
//清空旧的查询条件
|
||||
queryParamEntity.setTerms(new ArrayList<>());
|
||||
//添加一个查询条件
|
||||
queryParamEntity
|
||||
.where(RecordCreationEntity.creatorId,context.getAuthentication().getUser().getId())
|
||||
//客户端提交的参数 作为嵌套参数
|
||||
.nest().setTerms(oldParam);
|
||||
} else if (entity instanceof RecordCreationEntity) {
|
||||
((RecordCreationEntity) entity).setCreatorId(context.getAuthentication().getUser().getId());
|
||||
if (result instanceof RecordCreationEntity) {
|
||||
return userId.equals(((RecordCreationEntity) result).getCreatorId());
|
||||
} else if (result instanceof Collection) {
|
||||
Collection<?> collection = ((Collection) result);
|
||||
//删掉不能访问的对象
|
||||
collection.removeAll(collection.stream().filter((Object o) -> !matchCreatorId(o, userId))
|
||||
.collect(Collectors.toList()));
|
||||
} else {
|
||||
logger.warn("try validate query access,but entity not support, QueryParamEntity and RecordCreationEntity support now!");
|
||||
try {
|
||||
return userId.equals(PropertyUtils.getProperty(result, "creatorId"));
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ import org.hswebframework.web.authorization.access.ScriptDataAccessConfig;
|
||||
import org.hswebframework.web.authorization.define.AuthorizingContext;
|
||||
|
||||
/**
|
||||
* TODO 完成注释
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class ScriptDataAccessHandler implements DataAccessHandler {
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
package org.hswebframework.web.authorization;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import lombok.*;
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.authorization.annotation.RequiresDataAccess;
|
||||
import org.hswebframework.web.authorization.basic.aop.AopMethodAuthorizeDefinitionParser;
|
||||
import org.hswebframework.web.authorization.basic.aop.DefaultAopMethodAuthorizeDefinitionParser;
|
||||
import org.hswebframework.web.authorization.basic.handler.DefaultAuthorizingHandler;
|
||||
import org.hswebframework.web.authorization.basic.handler.access.DefaultDataAccessController;
|
||||
import org.hswebframework.web.authorization.define.AuthorizeDefinition;
|
||||
import org.hswebframework.web.authorization.define.AuthorizingContext;
|
||||
import org.hswebframework.web.authorization.define.Phased;
|
||||
import org.hswebframework.web.authorization.simple.*;
|
||||
import org.hswebframework.web.boost.aop.context.MethodInterceptorContext;
|
||||
import org.hswebframework.web.commons.entity.param.QueryParamEntity;
|
||||
import org.hswebframework.web.controller.message.ResponseMessage;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AuthorizeDefinitionTests {
|
||||
|
||||
@Mock
|
||||
private MethodInterceptorContext queryById;
|
||||
@Mock
|
||||
private MethodInterceptorContext dynamicQuery;
|
||||
|
||||
@Mock
|
||||
private Authentication authentication;
|
||||
|
||||
AopMethodAuthorizeDefinitionParser parser = new DefaultAopMethodAuthorizeDefinitionParser();
|
||||
|
||||
|
||||
@Before
|
||||
public void init() throws NoSuchMethodException {
|
||||
TestClass testClass = new TestClass();
|
||||
|
||||
QueryParamEntity entity = new QueryParamEntity();
|
||||
entity.where("id", "admin").or("name", "admin");
|
||||
|
||||
User user = User.builder().name("test").id("test")
|
||||
.orgId("400000")
|
||||
.password("admin").salt("1234").build();
|
||||
|
||||
//mock MethodInterceptorContext
|
||||
when(queryById.getMethod()).thenReturn(TestClass.class.getMethod("queryById", String.class));
|
||||
when(queryById.getTarget()).thenReturn(testClass);
|
||||
when(queryById.getParameter("id")).thenReturn(Optional.of("test"));
|
||||
when(queryById.getParams()).thenReturn(Collections.singletonMap("id", "test"));
|
||||
when(queryById.getInvokeResult()).thenReturn(ResponseMessage.ok(user));
|
||||
|
||||
|
||||
//mock MethodInterceptorContext
|
||||
when(dynamicQuery.getMethod()).thenReturn(TestClass.class.getMethod("dynamicQuery", QueryParamEntity.class));
|
||||
when(dynamicQuery.getTarget()).thenReturn(testClass);
|
||||
when(dynamicQuery.getParams()).thenReturn(Collections.singletonMap("paramEntity", entity));
|
||||
when(dynamicQuery.getParameter("paramEntity")).thenReturn(Optional.of(entity));
|
||||
|
||||
|
||||
//过滤字段
|
||||
AbstractDataAccessConfig fieldFilter = new SimpleFieldFilterDataAccessConfig("password", "salt");
|
||||
fieldFilter.setAction(Permission.ACTION_QUERY);
|
||||
|
||||
SimpleFiledScopeDataAccessConfig filedScope = new SimpleFiledScopeDataAccessConfig();
|
||||
filedScope.setAction(Permission.ACTION_QUERY);
|
||||
filedScope.setField("orgId");
|
||||
filedScope.setScopeType("org");
|
||||
filedScope.setScope(Collections.singleton("400000"));
|
||||
|
||||
//mock authentication
|
||||
when(authentication.getUser()).thenReturn(SimpleUser.builder().id("admin").name("admin").build());
|
||||
when(authentication.getPermissions()).thenReturn(Arrays.asList(SimplePermission.builder()
|
||||
.id("test")
|
||||
.dataAccesses(new HashSet<>(Arrays.asList(fieldFilter, filedScope)))
|
||||
|
||||
.actions(new HashSet<>(Arrays.asList(Permission.ACTION_QUERY, Permission.ACTION_UPDATE))).build()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseAuthorizeDefinition() {
|
||||
AuthorizeDefinition definition = parser.parse(queryById);
|
||||
|
||||
Assert.assertNotNull(definition);
|
||||
Assert.assertEquals(definition.getPermissions().size(), 1);
|
||||
Assert.assertEquals(definition.getPermissions().iterator().next(), "test");
|
||||
Assert.assertEquals(definition.getActions().iterator().next(), Permission.ACTION_QUERY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorizingHandler() {
|
||||
DefaultAuthorizingHandler handler = new DefaultAuthorizingHandler();
|
||||
|
||||
AuthorizeDefinition definition = parser.parse(queryById);
|
||||
|
||||
AuthorizingContext authorizingContext = new AuthorizingContext();
|
||||
authorizingContext.setAuthentication(authentication);
|
||||
authorizingContext.setDefinition(definition);
|
||||
authorizingContext.setParamContext(queryById);
|
||||
|
||||
handler.handle(authorizingContext);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据权限控制s
|
||||
*/
|
||||
@Test
|
||||
public void testDynamicQueryDataAccessHandler() {
|
||||
|
||||
DefaultAuthorizingHandler handler = new DefaultAuthorizingHandler();
|
||||
DefaultDataAccessController controller = new DefaultDataAccessController();
|
||||
handler.setDataAccessController(controller);
|
||||
|
||||
|
||||
AuthorizeDefinition definition = parser.parse(dynamicQuery);
|
||||
|
||||
//获取到请求参数
|
||||
QueryParamEntity entity = dynamicQuery.<QueryParamEntity>getParameter("paramEntity").orElseThrow(NullPointerException::new);
|
||||
System.out.println(JSON.toJSONString(entity, SerializerFeature.PrettyFormat));
|
||||
|
||||
AuthorizingContext authorizingContext = new AuthorizingContext();
|
||||
authorizingContext.setAuthentication(authentication);
|
||||
authorizingContext.setDefinition(definition);
|
||||
authorizingContext.setParamContext(dynamicQuery);
|
||||
|
||||
handler.handle(authorizingContext);
|
||||
|
||||
System.out.println(JSON.toJSONString(entity, SerializerFeature.PrettyFormat));
|
||||
|
||||
Assert.assertTrue(entity.getExcludes().size() == 2);
|
||||
Assert.assertTrue(entity.getTerms().size() == 2);
|
||||
Assert.assertTrue(entity.getTerms().get(1).getTerms().size() == 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据权限控制s
|
||||
*/
|
||||
@Test
|
||||
public void testGetDataAccessHandler() {
|
||||
|
||||
DefaultAuthorizingHandler handler = new DefaultAuthorizingHandler();
|
||||
DefaultDataAccessController controller = new DefaultDataAccessController();
|
||||
handler.setDataAccessController(controller);
|
||||
|
||||
|
||||
AuthorizeDefinition definition = parser.parse(queryById);
|
||||
|
||||
//响应结果
|
||||
Object response = queryById.getInvokeResult();
|
||||
|
||||
System.out.println(JSON.toJSONString(response, SerializerFeature.PrettyFormat));
|
||||
|
||||
AuthorizingContext authorizingContext = new AuthorizingContext();
|
||||
authorizingContext.setAuthentication(authentication);
|
||||
authorizingContext.setDefinition(definition);
|
||||
authorizingContext.setParamContext(queryById);
|
||||
|
||||
handler.handle(authorizingContext);
|
||||
|
||||
System.out.println(JSON.toJSONString(response, SerializerFeature.PrettyFormat));
|
||||
Assert.assertTrue(response instanceof ResponseMessage);
|
||||
Assert.assertTrue(((User) ((ResponseMessage) response).getResult()).getPassword() == null);
|
||||
Assert.assertTrue(((User) ((ResponseMessage) response).getResult()).getSalt() == null);
|
||||
}
|
||||
|
||||
@Authorize(permission = "test")
|
||||
public static class TestClass {
|
||||
|
||||
@Authorize(action = Permission.ACTION_QUERY, phased = Phased.after, dataAccess = @RequiresDataAccess)
|
||||
public ResponseMessage<User> queryById(String id) {
|
||||
return ResponseMessage.ok();
|
||||
}
|
||||
|
||||
@Authorize(action = Permission.ACTION_QUERY)
|
||||
@RequiresDataAccess
|
||||
public void dynamicQuery(QueryParamEntity paramEntity) {
|
||||
System.out.println(JSON.toJSON(paramEntity));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class User {
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String password;
|
||||
|
||||
private String salt;
|
||||
|
||||
private String orgId;
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user