优化权限解析

This commit is contained in:
zhouhao
2020-02-25 14:27:32 +08:00
parent 61d4fe9899
commit 9af9811f57
12 changed files with 206 additions and 104 deletions

View File

@@ -0,0 +1,155 @@
package org.hswebframework.web.authorization.basic.define;
import org.hswebframework.web.authorization.annotation.*;
import org.hswebframework.web.authorization.define.AopAuthorizeDefinition;
import org.hswebframework.web.authorization.define.ResourceActionDefinition;
import org.hswebframework.web.authorization.define.ResourceDefinition;
import org.springframework.core.annotation.AnnotatedElementUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class AopAuthorizeDefinitionParser {
private static final Set<Class<? extends Annotation>> types = new HashSet<>(Arrays.asList(
Authorize.class,
DataAccess.class,
Dimension.class,
Resource.class,
ResourceAction.class,
DataAccessType.class
));
private Set<Annotation> methodAnnotation;
private Set<Annotation> classAnnotation;
private Map<Class<? extends Annotation>, List<Annotation>> classAnnotationGroup;
private Map<Class<? extends Annotation>, List<Annotation>> methodAnnotationGroup;
private DefaultBasicAuthorizeDefinition definition;
AopAuthorizeDefinitionParser(Class<?> targetClass, Method method) {
definition = new DefaultBasicAuthorizeDefinition();
definition.setTargetClass(targetClass);
definition.setTargetMethod(method);
methodAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(method, types);
classAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(targetClass, types);
classAnnotationGroup = classAnnotation
.stream()
.collect(Collectors.groupingBy(Annotation::annotationType));
methodAnnotationGroup = methodAnnotation
.stream()
.collect(Collectors.groupingBy(Annotation::annotationType));
}
private void initClassAnnotation() {
for (Annotation annotation : classAnnotation) {
if (annotation instanceof Authorize) {
definition.putAnnotation(((Authorize) annotation));
}
if (annotation instanceof Resource) {
definition.putAnnotation(((Resource) annotation));
}
}
}
private void initMethodAnnotation() {
for (Annotation annotation : methodAnnotation) {
if (annotation instanceof Authorize) {
definition.putAnnotation(((Authorize) annotation));
}
if (annotation instanceof Resource) {
definition.putAnnotation(((Resource) annotation));
}
if (annotation instanceof Dimension) {
definition.putAnnotation(((Dimension) annotation));
}
}
}
private void initClassDataAccessAnnotation(){
for (Annotation annotation : classAnnotation) {
if (annotation instanceof DataAccessType ||
annotation instanceof DataAccess) {
for (ResourceDefinition resource : definition.getResources().getResources()) {
for (ResourceActionDefinition action : resource.getActions()) {
if (annotation instanceof DataAccessType) {
definition.putAnnotation(action, (DataAccessType) annotation);
} else {
definition.putAnnotation(action, (DataAccess) annotation);
}
}
}
}
}
}
private void initMethodDataAccessAnnotation() {
for (Annotation annotation : methodAnnotation) {
if (annotation instanceof ResourceAction) {
getAnnotationByType(Resource.class)
.map(res -> definition.getResources().getResource(res.id()).orElse(null))
.filter(Objects::nonNull)
.forEach(res -> {
ResourceAction ra = (ResourceAction) annotation;
ResourceActionDefinition action = definition.putAnnotation(res, ra);
getAnnotationByType(DataAccessType.class)
.findFirst()
.ifPresent(dat -> definition.putAnnotation(action, dat));
});
}
Optional<ResourceActionDefinition> actionDefinition = getAnnotationByType(Resource.class)
.map(res -> definition.getResources().getResource(res.id()).orElse(null))
.filter(Objects::nonNull)
.flatMap(res -> getAnnotationByType(ResourceAction.class)
.map(ra -> res.getAction(ra.id())
.orElse(null))
)
.filter(Objects::nonNull)
.findFirst();
if (annotation instanceof DataAccessType) {
actionDefinition.ifPresent(ra -> definition.putAnnotation(ra, (DataAccessType) annotation));
}
if (annotation instanceof DataAccess) {
actionDefinition.ifPresent(ra -> {
definition.putAnnotation(ra, (DataAccess) annotation);
getAnnotationByType(DataAccessType.class)
.findFirst()
.ifPresent(dat -> definition.putAnnotation(ra, dat));
});
}
}
}
AopAuthorizeDefinition parse() {
initClassAnnotation();
initClassDataAccessAnnotation();
initMethodAnnotation();
initMethodDataAccessAnnotation();
return definition;
}
private <T extends Annotation> Stream<T> getAnnotationByType(Class<T> type) {
return Optional.ofNullable(methodAnnotationGroup.getOrDefault(type, classAnnotationGroup.get(type)))
.map(Collection::stream)
.orElseGet(Stream::empty)
.map(type::cast);
}
}

View File

@@ -5,12 +5,14 @@ import lombok.*;
import org.hswebframework.web.authorization.annotation.*;
import org.hswebframework.web.authorization.define.*;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 默认权限权限定义
@@ -54,99 +56,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
));
public static AopAuthorizeDefinition from(Class targetClass, Method method) {
DefaultBasicAuthorizeDefinition definition = new DefaultBasicAuthorizeDefinition();
definition.setTargetClass(targetClass);
definition.setTargetMethod(method);
Set<Annotation> methodAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(method, types);
Set<Annotation> classAnnotation = AnnotatedElementUtils.findAllMergedAnnotations(targetClass, types);
Map<Class, Annotation> classAnnotationMap = classAnnotation
.stream()
.collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
Map<Class, Annotation> mapping = methodAnnotation
.stream()
.collect(Collectors.toMap(Annotation::annotationType, Function.identity()));
for (Annotation annotation : classAnnotation) {
if (annotation instanceof Authorize) {
definition.putAnnotation(((Authorize) annotation));
}
if (annotation instanceof Resource) {
definition.putAnnotation(((Resource) annotation));
}
}
for (Annotation annotation : methodAnnotation) {
if (annotation instanceof Authorize) {
definition.putAnnotation(((Authorize) annotation));
}
if (annotation instanceof Resource) {
definition.putAnnotation(((Resource) annotation));
}
if (annotation instanceof Dimension) {
definition.putAnnotation(((Dimension) annotation));
}
}
for (Annotation annotation : methodAnnotation) {
if (annotation instanceof ResourceAction) {
Optional.ofNullable(mapping.getOrDefault(Resource.class, classAnnotationMap.get(Resource.class)))
.map(Resource.class::cast)
.flatMap(res -> definition.getResources().getResource(res.id()))
.ifPresent(res -> {
ResourceAction ra = (ResourceAction) annotation;
ResourceActionDefinition action = definition.putAnnotation(res, ra);
Optional.ofNullable(mapping.get(DataAccessType.class))
.map(DataAccessType.class::cast)
.ifPresent(dat -> definition.putAnnotation(action, dat));
});
}
Optional<ResourceActionDefinition> actionDefinition = Optional.ofNullable(mapping.getOrDefault(Resource.class, classAnnotationMap.get(Resource.class)))
.map(Resource.class::cast)
.flatMap(res -> definition.getResources().getResource(res.id()))
.flatMap(res -> Optional.ofNullable(mapping.get(ResourceAction.class))
.map(ResourceAction.class::cast)
.flatMap(ra -> res.getAction(ra.id())));
if (annotation instanceof DataAccessType) {
actionDefinition.ifPresent(ra -> definition.putAnnotation(ra, (DataAccessType) annotation));
}
if (annotation instanceof DataAccess) {
actionDefinition.ifPresent(ra -> {
definition.putAnnotation(ra, (DataAccess) annotation);
Optional.ofNullable(mapping.get(DataAccessType.class))
.map(DataAccessType.class::cast)
.ifPresent(dat -> definition.putAnnotation(ra, dat));
});
}
}
for (Annotation annotation : classAnnotation) {
if (annotation instanceof DataAccessType||
annotation instanceof DataAccess) {
for (ResourceDefinition resource : definition.getResources().getResources()) {
for (ResourceActionDefinition action : resource.getActions()) {
if(annotation instanceof DataAccessType) {
definition.putAnnotation(action, (DataAccessType) annotation);
}else{
definition.putAnnotation(action, (DataAccess) annotation);
}
}
}
}
}
return definition;
return new AopAuthorizeDefinitionParser(targetClass,method).parse();
}
public void putAnnotation(Authorize ann) {
@@ -208,18 +118,27 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition {
}
DataAccessTypeDefinition typeDefinition = new DataAccessTypeDefinition();
for (DataAccessType dataAccessType : ann.type()) {
if(dataAccessType.ignore()){
continue;
}
typeDefinition.setId(dataAccessType.id());
typeDefinition.setName(dataAccessType.name());
typeDefinition.setController(dataAccessType.controller());
typeDefinition.setConfiguration(dataAccessType.configuration());
typeDefinition.setDescription(String.join("\n", dataAccessType.description()));
}
if(StringUtils.isEmpty(typeDefinition.getId())){
return;
}
definition.getDataAccess()
.getDataAccessTypes()
.add(typeDefinition);
}
public void putAnnotation(ResourceActionDefinition definition, DataAccessType dataAccessType) {
if(dataAccessType.ignore()){
return;
}
DataAccessTypeDefinition typeDefinition = new DataAccessTypeDefinition();
typeDefinition.setId(dataAccessType.id());
typeDefinition.setName(dataAccessType.name());

View File

@@ -10,6 +10,7 @@ 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.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@@ -32,7 +33,7 @@ public class AopAuthorizingControllerTest {
authentication.setUser(SimpleUser.builder().id("test").username("test").build());
// authentication.setPermissions(Arrays.asList(SimplePermission.builder().id("test").build()));
authentication.setPermissions(Collections.emptyList());
ReactiveAuthenticationHolder.addSupplier(new ReactiveAuthenticationSupplier() {
ReactiveAuthenticationHolder.setSupplier(new ReactiveAuthenticationSupplier() {
@Override
public Mono<Authentication> get(String userId) {
return Mono.empty();
@@ -73,7 +74,7 @@ public class AopAuthorizingControllerTest {
.dataAccesses(Collections.singleton(config))
.id("test").build()));
ReactiveAuthenticationHolder.addSupplier(new ReactiveAuthenticationSupplier() {
ReactiveAuthenticationHolder.setSupplier(new ReactiveAuthenticationSupplier() {
@Override
public Mono<Authentication> get(String userId) {
return Mono.empty();
@@ -109,7 +110,7 @@ public class AopAuthorizingControllerTest {
DimensionDataAccessConfig config2 = new DimensionDataAccessConfig();
config2.setAction("save");
config2.setScopeType("role");
ReactiveAuthenticationHolder.addSupplier(new ReactiveAuthenticationSupplier() {
ReactiveAuthenticationHolder.setSupplier(new ReactiveAuthenticationSupplier() {
@Override
public Mono<Authentication> get(String userId) {
return Mono.empty();

View File

@@ -33,6 +33,7 @@ public class TestController implements ReactiveCrudController<TestEntity, String
@QueryAction
@FieldDataAccess
@DimensionDataAccess(ignore = true)
public Mono<QueryParam> queryUser(QueryParam queryParam) {
return Mono.just(queryParam);
}

View File

@@ -26,7 +26,7 @@ public class DefaultBasicAuthorizeDefinitionTest {
Assert.assertTrue(resource.hasAction(Arrays.asList("add")));
Assert.assertTrue(resource.getAction("add")
.map(act->act.getDataAccess().getType("user_own"))
.map(act->act.getDataAccess().getType("user_own_data"))
.isPresent());
}