Merge branch 'master' into spring-boot3

# Conflicts:
#	hsweb-authorization/hsweb-authorization-api/pom.xml
#	hsweb-authorization/hsweb-authorization-basic/pom.xml
#	hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingControllerTest.java
#	hsweb-authorization/hsweb-authorization-oauth2/pom.xml
#	hsweb-authorization/pom.xml
#	hsweb-commons/hsweb-commons-api/pom.xml
#	hsweb-commons/hsweb-commons-crud/pom.xml
#	hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormRepositoryRegistrar.java
#	hsweb-commons/pom.xml
#	hsweb-concurrent/hsweb-concurrent-cache/pom.xml
#	hsweb-concurrent/pom.xml
#	hsweb-core/pom.xml
#	hsweb-datasource/hsweb-datasource-api/pom.xml
#	hsweb-datasource/hsweb-datasource-jta/pom.xml
#	hsweb-datasource/hsweb-datasource-web/pom.xml
#	hsweb-datasource/pom.xml
#	hsweb-logging/hsweb-access-logging-aop/pom.xml
#	hsweb-logging/hsweb-access-logging-api/pom.xml
#	hsweb-logging/pom.xml
#	hsweb-starter/pom.xml
#	hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/pom.xml
#	hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/pom.xml
#	hsweb-system/hsweb-system-authorization/hsweb-system-authorization-oauth2/pom.xml
#	hsweb-system/hsweb-system-authorization/pom.xml
#	hsweb-system/hsweb-system-dictionary/pom.xml
#	hsweb-system/hsweb-system-file/pom.xml
#	hsweb-system/pom.xml
#	pom.xml
This commit is contained in:
zhouhao
2024-12-20 13:36:18 +08:00
38 changed files with 725 additions and 208 deletions

View File

@@ -64,43 +64,41 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor
MethodInterceptorHolder holder,
AuthorizingContext context,
Supplier<? extends Publisher<?>> invoker) {
MethodInterceptorContext interceptorContext = holder.createParamContext(invoker.get());
context.setParamContext(interceptorContext);
return this
.invokeReactive(
Authentication
.currentReactive()
.switchIfEmpty(Mono.error(UnAuthorizedException.NoStackTrace::new))
.flatMap(auth -> {
context.setAuthentication(auth);
//响应式不再支持数据权限控制
return authorizingHandler.handRBACAsync(context);
}),
(Publisher<?>) interceptorContext.getInvokeResult());
}
return Authentication
.currentReactive()
.switchIfEmpty(Mono.error(UnAuthorizedException::new))
.flatMapMany(auth -> {
context.setAuthentication(auth);
Function<Runnable, Publisher> afterRuner = runnable -> {
MethodInterceptorContext interceptorContext = holder.createParamContext(invoker.get());
context.setParamContext(interceptorContext);
runnable.run();
return (Publisher<?>) interceptorContext.getInvokeResult();
};
if (context.getDefinition().getPhased() != Phased.after) {
authorizingHandler.handRBAC(context);
if (context.getDefinition().getResources().getPhased() != Phased.after) {
authorizingHandler.handleDataAccess(context);
return invoker.get();
} else {
return afterRuner.apply(() -> authorizingHandler.handleDataAccess(context));
}
private Publisher<?> invokeReactive(Mono<?> before, Publisher<?> source) {
if (source instanceof Mono) {
return before.then((Mono<Object>) source);
}
return before.thenMany(source);
}
} else {
if (context.getDefinition().getResources().getPhased() != Phased.after) {
authorizingHandler.handleDataAccess(context);
return invoker.get();
} else {
return afterRuner.apply(() -> {
authorizingHandler.handRBAC(context);
authorizingHandler.handleDataAccess(context);
});
}
}
});
private <T> T invokeReactive(MethodInvocation invocation) {
if (Mono.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
return (T) Mono.defer(() -> doProceed(invocation));
}
if (Flux.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
return (T) Flux.defer(() -> doProceed(invocation));
}
return doProceed(invocation);
}
@SneakyThrows
private <T> T doProceed(MethodInvocation invocation) {
return (T) invocation.proceed();
}
@@ -110,9 +108,12 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor
MethodInterceptorContext paramContext = holder.createParamContext();
AuthorizeDefinition definition = aopMethodAuthorizeDefinitionParser.parse(methodInvocation
.getThis()
.getClass(), methodInvocation.getMethod(), paramContext);
AuthorizeDefinition definition = aopMethodAuthorizeDefinitionParser
.parse(methodInvocation
.getThis()
.getClass(),
methodInvocation.getMethod(),
paramContext);
Object result = null;
boolean isControl = false;
if (null != definition && !definition.isEmpty()) {
@@ -123,16 +124,12 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor
Class<?> returnType = methodInvocation.getMethod().getReturnType();
//handle reactive method
if (Publisher.class.isAssignableFrom(returnType)) {
Publisher publisher = handleReactive0(definition, holder, context, () -> doProceed(methodInvocation));
if (Mono.class.isAssignableFrom(returnType)) {
return Mono.from(publisher);
} else if (Flux.class.isAssignableFrom(returnType)) {
return Flux.from(publisher);
}
throw new UnsupportedOperationException("unsupported reactive type:" + returnType);
return handleReactive0(definition, holder, context, () -> invokeReactive(methodInvocation));
}
Authentication authentication = Authentication.current().orElseThrow(UnAuthorizedException::new);
Authentication authentication = Authentication
.current()
.orElseThrow(UnAuthorizedException.NoStackTrace::new);
context.setAuthentication(authentication);
isControl = true;

View File

@@ -1,6 +1,7 @@
package org.hswebframework.web.authorization.basic.handler;
import org.hswebframework.web.authorization.define.AuthorizingContext;
import reactor.core.publisher.Mono;
/**
* aop方式权限控制处理器
@@ -8,10 +9,17 @@ import org.hswebframework.web.authorization.define.AuthorizingContext;
* @author zhouhao
*/
public interface AuthorizingHandler {
void handRBAC(AuthorizingContext context);
default Mono<Void> handRBACAsync(AuthorizingContext context) {
return Mono.fromRunnable(() -> handRBAC(context));
}
@Deprecated
void handleDataAccess(AuthorizingContext context);
@Deprecated
default void handle(AuthorizingContext context) {
handRBAC(context);
handleDataAccess(context);

View File

@@ -1,5 +1,6 @@
package org.hswebframework.web.authorization.basic.handler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.hswebframework.web.authorization.Authentication;
import org.hswebframework.web.authorization.Permission;
@@ -14,6 +15,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import reactor.core.publisher.Mono;
import java.util.concurrent.TimeUnit;
/**
* @author zhouhao
@@ -51,15 +55,54 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler {
}
@Override
public Mono<Void> handRBACAsync(AuthorizingContext context) {
return this
.handleEventAsync(context, HandleType.RBAC)
.doOnNext(handled -> {
//没有自定义事件处理
if (!handled) {
handleRBAC(context.getAuthentication(), context.getDefinition());
}
})
.then();
}
private Mono<Boolean> handleEventAsync(AuthorizingContext context, HandleType type) {
if (null != eventPublisher) {
AuthorizingHandleBeforeEvent event = new AuthorizingHandleBeforeEvent(context, type);
return event
.publish(eventPublisher)
.then(Mono.fromCallable(() -> {
if (!event.isExecute()) {
if (event.isAllow()) {
return true;
} else {
throw new AccessDenyException.NoStackTrace(event.getMessage());
}
}
return false;
}));
}
return Mono.just(false);
}
@SneakyThrows
private boolean handleEvent(AuthorizingContext context, HandleType type) {
if (null != eventPublisher) {
AuthorizingHandleBeforeEvent event = new AuthorizingHandleBeforeEvent(context, type);
eventPublisher.publishEvent(event);
if (event.hasListener()) {
event
.getAsync()
.toFuture()
.get(10, TimeUnit.SECONDS);
}
if (!event.isExecute()) {
if (event.isAllow()) {
return true;
} else {
throw new AccessDenyException(event.getMessage());
throw new AccessDenyException.NoStackTrace(event.getMessage());
}
}
}
@@ -81,21 +124,26 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler {
DataAccessController finalAccessController = dataAccessController;
Authentication autz = context.getAuthentication();
boolean isAccess = context.getDefinition()
.getResources()
.getDataAccessResources()
.stream()
.allMatch(resource -> {
Permission permission = autz.getPermission(resource.getId()).orElseThrow(AccessDenyException::new);
return resource.getDataAccessAction()
.stream()
.allMatch(act -> permission.getDataAccesses(act.getId())
.stream()
.allMatch(dataAccessConfig -> finalAccessController.doAccess(dataAccessConfig, context)));
boolean isAccess = context
.getDefinition()
.getResources()
.getDataAccessResources()
.stream()
.allMatch(resource -> {
Permission permission = autz
.getPermission(resource.getId())
.orElseThrow(AccessDenyException.NoStackTrace::new);
return resource
.getDataAccessAction()
.stream()
.allMatch(act -> permission
.getDataAccesses(act.getId())
.stream()
.allMatch(dataAccessConfig -> finalAccessController.doAccess(dataAccessConfig, context)));
});
});
if (!isAccess) {
throw new AccessDenyException(context.getDefinition().getMessage());
throw new AccessDenyException.NoStackTrace(context.getDefinition().getMessage());
}
}
@@ -105,7 +153,7 @@ public class DefaultAuthorizingHandler implements AuthorizingHandler {
ResourcesDefinition resources = definition.getResources();
if (!resources.hasPermission(authentication)) {
throw new AccessDenyException(definition.getMessage(),definition.getDescription());
throw new AccessDenyException.NoStackTrace(definition.getMessage(), definition.getDescription());
}
}
}