增加维度数据权限

This commit is contained in:
zhou-hao
2019-11-19 18:26:17 +08:00
parent 0cdfc2bbef
commit 4bcef2f250
31 changed files with 923 additions and 64 deletions

View File

@@ -70,6 +70,7 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor
context.setAuthentication(auth);
Function<Runnable, Publisher> afterRuner = runnable -> {
MethodInterceptorContext interceptorContext = holder.createParamContext(invoker.get());
context.setParamContext(interceptorContext);
runnable.run();
return (Publisher<?>) interceptorContext.getInvokeResult();
};

View File

@@ -163,6 +163,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
resource.setId(ann.id());
resource.setName(ann.name());
resource.setLogical(ann.logical());
resource.setPhased(ann.phased());
resource.setDescription(String.join("\n", ann.description()));
for (ResourceAction action : ann.actions()) {
putAnnotation(resource, action);
@@ -193,6 +194,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
typeDefinition.setId(dataAccessType.id());
typeDefinition.setName(dataAccessType.name());
typeDefinition.setController(dataAccessType.controller());
typeDefinition.setConfiguration(dataAccessType.configuration());
typeDefinition.setDescription(String.join("\n", dataAccessType.description()));
}
definition.getDataAccess()
@@ -205,6 +207,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
typeDefinition.setId(dataAccessType.id());
typeDefinition.setName(dataAccessType.name());
typeDefinition.setController(dataAccessType.controller());
typeDefinition.setConfiguration(dataAccessType.configuration());
typeDefinition.setDescription(String.join("\n", dataAccessType.description()));
definition.getDataAccess()
.getDataAccessTypes()

View File

@@ -0,0 +1,60 @@
package org.hswebframework.web.authorization.basic.handler.access;
import lombok.Getter;
import lombok.Setter;
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
import org.hswebframework.utils.ClassUtils;
import org.hswebframework.web.aop.MethodInterceptorContext;
import org.hswebframework.web.authorization.Authentication;
import org.hswebframework.web.authorization.Dimension;
import org.hswebframework.web.authorization.DimensionType;
import org.hswebframework.web.authorization.define.AuthorizingContext;
import org.hswebframework.web.crud.web.reactive.*;
import java.util.List;
@Getter
@Setter
public class DataAccessHandlerContext {
private Class<?> entityType;
private ReactiveRepository<?, Object> repository;
private Authentication authentication;
private List<Dimension> dimensions;
private MethodInterceptorContext paramContext;
public static DataAccessHandlerContext of(AuthorizingContext context, String type) {
DataAccessHandlerContext requestContext = new DataAccessHandlerContext();
Authentication authentication = context.getAuthentication();
requestContext.setDimensions(authentication.getDimensions(type));
requestContext.setAuthentication(context.getAuthentication());
requestContext.setParamContext(context.getParamContext());
Object target = context.getParamContext().getTarget();
Class entityType = ClassUtils.getGenericType(org.springframework.util.ClassUtils.getUserClass(target));
if (entityType != Object.class) {
requestContext.setEntityType(entityType);
}
if (target instanceof ReactiveQueryController) {
requestContext.setRepository(((ReactiveQueryController) target).getRepository());
} else if (target instanceof ReactiveSaveController) {
requestContext.setRepository(((ReactiveSaveController) target).getRepository());
} else if (target instanceof ReactiveDeleteController) {
requestContext.setRepository(((ReactiveDeleteController) target).getRepository());
} else if (target instanceof ReactiveServiceQueryController) {
requestContext.setRepository(((ReactiveServiceQueryController) target).getService().getRepository());
} else if (target instanceof ReactiveServiceSaveController) {
requestContext.setRepository(((ReactiveServiceSaveController) target).getService().getRepository());
} else if (target instanceof ReactiveServiceDeleteController) {
requestContext.setRepository(((ReactiveServiceDeleteController) target).getService().getRepository());
}
// TODO: 2019-11-18 not reactive implements
return requestContext;
}
}

View File

@@ -30,7 +30,8 @@ public final class DefaultDataAccessController implements DataAccessController {
throw new UnsupportedOperationException();
}
this.parent = parent;
addHandler(new FieldFilterDataAccessHandler());
addHandler(new FieldFilterDataAccessHandler())
.addHandler(new DimensionDataAccessHandler());
}
@Override

View File

@@ -0,0 +1,382 @@
package org.hswebframework.web.authorization.basic.handler.access;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.hswebframework.ezorm.core.param.Param;
import org.hswebframework.ezorm.core.param.QueryParam;
import org.hswebframework.web.api.crud.entity.Entity;
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
import org.hswebframework.web.authorization.Authentication;
import org.hswebframework.web.authorization.Dimension;
import org.hswebframework.web.authorization.Permission;
import org.hswebframework.web.authorization.access.DataAccessConfig;
import org.hswebframework.web.authorization.access.DataAccessHandler;
import org.hswebframework.web.authorization.annotation.DimensionDataAccess;
import org.hswebframework.web.authorization.define.AuthorizingContext;
import org.hswebframework.web.authorization.exception.AccessDenyException;
import org.hswebframework.web.authorization.simple.DimensionDataAccessConfig;
import org.hswebframework.web.bean.FastBeanCopier;
import org.hswebframework.web.utils.AnnotationUtils;
import org.reactivestreams.Publisher;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j
public class DimensionDataAccessHandler implements DataAccessHandler {
@Override
public boolean isSupport(DataAccessConfig access) {
return access instanceof DimensionDataAccessConfig;
}
@Override
public boolean handle(DataAccessConfig access, AuthorizingContext context) {
DimensionDataAccessConfig config = ((DimensionDataAccessConfig) access);
DataAccessHandlerContext requestContext = DataAccessHandlerContext.of(context, config.getScopeType());
if (!checkSupported(config, requestContext)) {
return false;
}
switch (access.getAction()) {
case Permission.ACTION_QUERY:
case Permission.ACTION_GET:
return doHandleQuery(config, requestContext);
case Permission.ACTION_ADD:
case Permission.ACTION_SAVE:
case Permission.ACTION_UPDATE:
return doHandleUpdate(config, requestContext);
case Permission.ACTION_DELETE:
return doHandleDelete(config, requestContext);
default:
if (log.isDebugEnabled()) {
log.debug("data access [{}] not support for {}", config.getType().getId(), access.getAction());
}
return true;
}
}
@SneakyThrows
protected String getProperty(DimensionDataAccessConfig cfg,
DataAccessHandlerContext ct) {
return Optional.ofNullable(
getMappingInfo(ct).get(cfg.getScopeType()))
.map(MappingInfo::getProperty)
.orElseGet(() -> {
log.warn("{} not supported dimension data access", ct.getParamContext().getMethod());
return null;
});
}
protected boolean checkSupported(DimensionDataAccessConfig cfg, DataAccessHandlerContext ctx) {
Authentication authentication = ctx.getAuthentication();
/*
DataAccessHelper.assert()
*/
if (CollectionUtils.isEmpty(ctx.getDimensions())) {
log.warn("user:[{}] dimension not setup", authentication.getUser().getId());
return false;
}
if (!getMappingInfo(ctx).containsKey(cfg.getScopeType())) {
log.warn("{} not supported dimension data access.see annotation: @DimensionDataAccess", ctx.getParamContext().getMethod());
return false;
}
return true;
}
protected boolean doHandleDelete(DimensionDataAccessConfig cfg,
DataAccessHandlerContext context) {
// TODO: 2019-11-18
return doHandleUpdate(cfg, context);
}
@SuppressWarnings("all")
protected Object handleUpdateById(DimensionDataAccessConfig config,
DataAccessHandlerContext context,
MappingInfo mappingInfo,
Object id) {
List<Dimension> dimensions = context.getDimensions();
Set<Object> scope = CollectionUtils.isNotEmpty(config.getScope()) ?
config.getScope() :
dimensions
.stream()
.map(Dimension::getId)
.collect(Collectors.toSet());
Function<Collection<Object>, Mono<Void>> reactiveCheck = obj -> context
.getRepository()
.findById(obj)
.doOnNext(r -> {
Object val = FastBeanCopier.copy(r, new HashMap<>(), FastBeanCopier.include(mappingInfo.getProperty()))
.get(mappingInfo.getProperty());
if (!StringUtils.isEmpty(val)
&& !scope.contains(val)) {
throw new AccessDenyException();
}
})
.then();
if (id instanceof Publisher) {
if (id instanceof Mono) {
return ((Mono) id)
.flatMap(r -> reactiveCheck.apply(r instanceof Collection ? ((Collection) r) : Collections.singleton(r)))
.then((Mono) id);
}
if (id instanceof Flux) {
return ((Flux) id)
.collectList()
.flatMap(reactiveCheck)
.thenMany((Flux) id);
}
}
Collection<Object> idVal = id instanceof Collection ? ((Collection) id) : Collections.singleton(id);
Object result = context.getParamContext().getInvokeResult();
if (result instanceof Mono) {
context.getParamContext()
.setInvokeResult(((Mono) result)
.flatMap(res -> {
return reactiveCheck.apply(idVal).thenReturn(res);
}));
} else if (result instanceof Flux) {
context.getParamContext()
.setInvokeResult(((Flux) result)
.flatMap(res -> {
return reactiveCheck.apply(idVal).thenReturn(res);
}));
} else {
// TODO: 2019-11-19 非响应式处理
}
return id;
}
protected boolean doHandleUpdate(DimensionDataAccessConfig cfg,
DataAccessHandlerContext context) {
MappingInfo info = getMappingInfo(context).get(cfg.getScopeType());
if (info != null) {
if (info.idParamIndex != -1) {
Object param = context.getParamContext().getArguments()[info.idParamIndex];
context.getParamContext().getArguments()[info.idParamIndex] = handleUpdateById(cfg, context, info, param);
return true;
}
} else {
return true;
}
boolean reactive = context.getParamContext()
.handleReactiveArguments(publisher -> {
if (publisher instanceof Mono) {
return Mono.from(publisher)
.flatMap(payload -> applyReactiveUpdatePayload(cfg, info, Collections.singleton(payload), context)
.thenReturn(payload));
}
if (publisher instanceof Flux) {
return Flux.from(publisher)
.collectList()
.flatMapMany(list ->
applyReactiveUpdatePayload(cfg, info, list, context)
.flatMapIterable(v -> list));
}
return publisher;
});
if (!reactive) {
applyUpdatePayload(cfg, info, Arrays
.stream(context.getParamContext().getArguments())
.flatMap(obj -> {
if (obj instanceof Collection) {
return ((Collection<?>) obj).stream();
}
return Stream.of(obj);
})
.filter(Entity.class::isInstance)
.collect(Collectors.toSet()), context);
return true;
}
return true;
}
protected void applyUpdatePayload(DimensionDataAccessConfig config,
MappingInfo mappingInfo,
Collection<?> payloads,
DataAccessHandlerContext context) {
List<Dimension> dimensions = context.getDimensions();
Set<Object> scope = CollectionUtils.isNotEmpty(config.getScope()) ?
config.getScope() :
dimensions
.stream()
.map(Dimension::getId)
.collect(Collectors.toSet());
for (Object payload : payloads) {
if (!(payload instanceof Entity)) {
continue;
}
if (payload instanceof Param) {
applyQueryParam(config, context, ((Param) payload));
continue;
}
String property = mappingInfo.getProperty();
Map<String, Object> map = FastBeanCopier.copy(payload, new HashMap<>(), FastBeanCopier.include(property));
Object value = map.get(property);
if (StringUtils.isEmpty(value)) {
if (dimensions.size() == 1) {
map.put(property, dimensions.get(0).getId());
FastBeanCopier.copy(map, payload, property);
}
continue;
}
if (CollectionUtils.isNotEmpty(scope)) {
if (!scope.contains(value)) {
throw new AccessDenyException();
}
}
}
}
protected Mono<Void> applyReactiveUpdatePayload(DimensionDataAccessConfig config,
MappingInfo info,
Collection<?> payloads,
DataAccessHandlerContext context) {
return Mono.fromRunnable(() -> applyUpdatePayload(config, info, payloads, context));
}
protected boolean doHandleQuery(DimensionDataAccessConfig cfg, DataAccessHandlerContext requestContext) {
boolean reactive = requestContext.getParamContext().handleReactiveArguments(publisher -> {
if (publisher instanceof Mono) {
return Mono
.from(publisher)
.flatMap(param -> this
.applyReactiveQueryParam(cfg, requestContext, param)
.thenReturn(param));
}
return publisher;
});
if (!reactive) {
Object[] args = requestContext.getParamContext().getArguments();
this.applyQueryParam(cfg, requestContext, args);
}
return true;
}
protected String getTermType(DimensionDataAccessConfig cfg) {
return "in";
}
protected void applyQueryParam(DimensionDataAccessConfig cfg,
DataAccessHandlerContext requestContext,
Param param) {
Set<Object> scope = CollectionUtils.isNotEmpty(cfg.getScope()) ?
cfg.getScope() :
requestContext.getDimensions()
.stream()
.map(Dimension::getId)
.collect(Collectors.toSet());
QueryParamEntity entity = new QueryParamEntity();
entity.setTerms(new ArrayList<>(param.getTerms()));
entity.toNestQuery(query ->
query.where(
getProperty(cfg, requestContext),
getTermType(cfg),
scope));
param.setTerms(entity.getTerms());
}
protected void applyQueryParam(DimensionDataAccessConfig cfg,
DataAccessHandlerContext requestContext,
Object... params) {
for (Object param : params) {
if (param instanceof QueryParam) {
applyQueryParam(cfg, requestContext, (QueryParam) param);
}
}
}
protected Mono<Void> applyReactiveQueryParam(DimensionDataAccessConfig cfg,
DataAccessHandlerContext requestContext,
Object... param) {
return Mono.fromRunnable(() -> applyQueryParam(cfg, requestContext, param));
}
private Map<Method, Map<String, MappingInfo>> cache = new ConcurrentHashMap<>();
public Map<String, MappingInfo> getMappingInfo(DataAccessHandlerContext context) {
return getMappingInfo(ClassUtils.getUserClass(context.getParamContext().getTarget()), context.getParamContext().getMethod());
}
private Set<Class<? extends Annotation>> ann = new HashSet<>(Arrays.asList(DimensionDataAccess.class, DimensionDataAccess.Mapping.class));
private Map<String, MappingInfo> getMappingInfo(Class target, Method method) {
return cache.computeIfAbsent(method, m -> {
Set<Annotation> methodAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(method, ann);
Set<Annotation> classAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(target, ann);
if (CollectionUtils.isEmpty(methodAnnotation)) {
return Collections.emptyMap();
}
List<Annotation> all = new ArrayList<>(classAnnotation);
all.addAll(methodAnnotation);
Map<String, MappingInfo> mappingInfoMap = new HashMap<>();
for (Annotation annotation : all) {
if (annotation instanceof DimensionDataAccess) {
for (DimensionDataAccess.Mapping mapping : ((DimensionDataAccess) annotation).mapping()) {
mappingInfoMap.put(mapping.dimensionType(), MappingInfo.of(mapping));
}
}
if (annotation instanceof DimensionDataAccess.Mapping) {
mappingInfoMap.put(((DimensionDataAccess.Mapping) annotation).dimensionType(), MappingInfo.of(((DimensionDataAccess.Mapping) annotation)));
}
}
return mappingInfoMap;
});
}
@Getter
@Setter
@AllArgsConstructor
static class MappingInfo {
String dimension;
String property;
int idParamIndex;
static MappingInfo of(DimensionDataAccess.Mapping mapping) {
return new MappingInfo(mapping.dimensionType(), mapping.property(), mapping.idParamIndex());
}
}
}

View File

@@ -39,6 +39,7 @@ public class FieldFilterDataAccessHandler implements DataAccessHandler {
case Permission.ACTION_GET:
return doQueryAccess(filterDataAccessConfig, context);
case Permission.ACTION_ADD:
case Permission.ACTION_SAVE:
case Permission.ACTION_UPDATE:
return doUpdateAccess(filterDataAccessConfig, context);
default:

View File

@@ -2,36 +2,20 @@ package org.hswebframework.web.authorization.basic.aop;
import org.hswebframework.ezorm.core.param.Param;
import org.hswebframework.ezorm.core.param.QueryParam;
import org.hswebframework.web.authorization.Authentication;
import org.hswebframework.web.authorization.ReactiveAuthenticationHolder;
import org.hswebframework.web.authorization.ReactiveAuthenticationSupplier;
import org.hswebframework.web.authorization.User;
import org.hswebframework.web.authorization.basic.handler.access.FieldFilterDataAccessHandler;
import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenParser;
import org.hswebframework.ezorm.core.param.Term;
import org.hswebframework.web.authorization.*;
import org.hswebframework.web.authorization.exception.AccessDenyException;
import org.hswebframework.web.authorization.exception.UnAuthorizedException;
import org.hswebframework.web.authorization.simple.SimpleAuthentication;
import org.hswebframework.web.authorization.simple.SimpleFieldFilterDataAccessConfig;
import org.hswebframework.web.authorization.simple.SimplePermission;
import org.hswebframework.web.authorization.simple.SimpleUser;
import org.hswebframework.web.authorization.token.ParsedToken;
import org.junit.Before;
import org.hswebframework.web.authorization.simple.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import static org.junit.Assert.*;
import java.util.*;
import java.util.function.Function;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplication.class)
@@ -76,10 +60,10 @@ public class AopAuthorizingControllerTest {
}
@Test
public void testFiledDeny(){
public void testFiledDeny() {
SimpleAuthentication authentication = new SimpleAuthentication();
SimpleFieldFilterDataAccessConfig config=new SimpleFieldFilterDataAccessConfig();
SimpleFieldFilterDataAccessConfig config = new SimpleFieldFilterDataAccessConfig();
config.setAction("query");
config.setFields(new HashSet<>(Arrays.asList("name")));
@@ -104,13 +88,84 @@ public class AopAuthorizingControllerTest {
testController.queryUser(new QueryParam())
.map(Param::getExcludes)
.as(StepVerifier::create)
.expectNextMatches(f->f.contains("name"))
.expectNextMatches(f -> f.contains("name"))
.verifyComplete();
testController.queryUser(Mono.just(new QueryParam()))
.map(Param::getExcludes)
.as(StepVerifier::create)
.expectNextMatches(f->f.contains("name"))
.expectNextMatches(f -> f.contains("name"))
.verifyComplete();
}
@Test
public void testDimensionDataAccess() {
SimpleAuthentication authentication = new SimpleAuthentication();
DimensionDataAccessConfig config = new DimensionDataAccessConfig();
config.setAction("query");
config.setScopeType("role");
DimensionDataAccessConfig config2 = new DimensionDataAccessConfig();
config2.setAction("save");
config2.setScopeType("role");
ReactiveAuthenticationHolder.addSupplier(new ReactiveAuthenticationSupplier() {
@Override
public Mono<Authentication> get(String userId) {
return Mono.empty();
}
@Override
public Mono<Authentication> get() {
return Mono.just(authentication);
}
});
authentication.setUser(SimpleUser.builder().id("test").username("test").build());
authentication.setPermissions(Arrays.asList(SimplePermission.builder()
.actions(new HashSet<>(Arrays.asList("query", "save")))
.dataAccesses(new HashSet<>(Arrays.asList(config, config2)))
.id("test").build()));
authentication.setDimensions(Collections.singletonList(Dimension.of("test", "test", DefaultDimensionType.role)));
testController.queryUserByDimension(Mono.just(new QueryParam()))
.map(Param::getTerms)
.flatMapIterable(Function.identity())
.next()
.map(Term::getValue)
.<Collection<Object>>map(Collection.class::cast)
.flatMapIterable(Function.identity())
.next()
.as(StepVerifier::create)
.expectNextMatches("test"::equals)
.verifyComplete();
TestEntity testEntity = new TestEntity();
testEntity.setRoleId("123");
testController.save(Mono.just(testEntity))
.as(StepVerifier::create)
.expectError(AccessDenyException.class)
.verify();
testController.add(Mono.just(testEntity))
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
testController.update(testEntity.getId(),Mono.just(testEntity))
.as(StepVerifier::create)
.expectError(AccessDenyException.class)
.verify();
testEntity = new TestEntity();
testEntity.setRoleId("test");
testController.save(Mono.just(testEntity))
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
}
}

View File

@@ -1,11 +1,13 @@
package org.hswebframework.web.authorization.basic.aop;
import org.hswebframework.web.authorization.basic.configuration.EnableAopAuthorize;
import org.hswebframework.web.crud.annotation.EnableEasyormRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableAopAuthorize
@EnableEasyormRepository("org.hswebframework.web.authorization.basic.aop")
public class TestApplication {
public static void main(String[] args) {

View File

@@ -1,18 +1,21 @@
package org.hswebframework.web.authorization.basic.aop;
import org.hswebframework.ezorm.core.param.QueryParam;
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
import org.hswebframework.web.authorization.Authentication;
import org.hswebframework.web.authorization.User;
import org.hswebframework.web.authorization.access.DataAccessConfig;
import org.hswebframework.web.authorization.annotation.*;
import org.hswebframework.web.authorization.define.Phased;
import org.hswebframework.web.authorization.exception.UnAuthorizedException;
import org.hswebframework.web.crud.web.reactive.ReactiveCrudController;
import org.hswebframework.web.crud.web.reactive.ReactiveQueryController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@Resource(id = "test", name = "测试")
public class TestController {
public class TestController implements ReactiveCrudController<TestEntity, String> {
@QueryAction
public Mono<User> getUser() {
@@ -28,15 +31,41 @@ public class TestController {
.map(Authentication::getUser);
}
@QueryAction(dataAccess = @DataAccess(type = @DataAccessType(id= DataAccessConfig.DefaultType.DENY_FIELDS,name = "禁止访问字段")))
@QueryAction
@FieldDataAccess
public Mono<QueryParam> queryUser(QueryParam queryParam) {
return Mono.just(queryParam);
}
@QueryAction(dataAccess = @DataAccess(type = @DataAccessType(id= DataAccessConfig.DefaultType.DENY_FIELDS,name = "禁止访问字段")))
@QueryAction
@FieldDataAccess
public Mono<QueryParam> queryUser(Mono<QueryParam> queryParam) {
return queryParam;
}
@QueryAction
@TestDataAccess
public Mono<QueryParam> queryUserByDimension(Mono<QueryParam> queryParam) {
return queryParam;
}
@SaveAction
@TestDataAccess
public Mono<TestEntity> save(Mono<TestEntity> param) {
return param;
}
@Override
@TestDataAccess(idParamIndex = 0,phased = Phased.after)
public Mono<Boolean> update(String id, Mono<TestEntity> payload) {
return ReactiveCrudController.super.update(id, payload);
}
@Autowired
ReactiveRepository<TestEntity, String> reactiveRepository;
@Override
public ReactiveRepository<TestEntity, String> getRepository() {
return reactiveRepository;
}
}

View File

@@ -0,0 +1,22 @@
package org.hswebframework.web.authorization.basic.aop;
import org.hswebframework.web.authorization.annotation.DimensionDataAccess;
import org.hswebframework.web.authorization.define.Phased;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@DimensionDataAccess
@DimensionDataAccess.Mapping(dimensionType = "role", property = "roleId")
public @interface TestDataAccess {
@AliasFor(annotation = DimensionDataAccess.Mapping.class)
int idParamIndex() default -1;
@AliasFor(annotation = DimensionDataAccess.class)
Phased phased() default Phased.before;
}

View File

@@ -0,0 +1,20 @@
package org.hswebframework.web.authorization.basic.aop;
import lombok.Getter;
import lombok.Setter;
import org.hswebframework.web.api.crud.entity.GenericEntity;
import reactor.core.publisher.Mono;
import javax.persistence.Column;
import javax.persistence.Table;
@Getter
@Setter
@Table(name = "test_entity")
public class TestEntity extends GenericEntity<String> {
@Column
private String roleId;
}

View File

@@ -7,4 +7,9 @@ hsweb:
permissions-simple:
user-token:
- get
- update
- update
easyorm:
dialect: h2
logging:
level:
org.hswebframework: debug