From 63a15a1af37e6df8a94ca6fad5b7152f16bdc653 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Sat, 30 Jul 2022 10:08:54 +0800 Subject: [PATCH 01/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/CommonWebFluxConfiguration.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java index 9a2c8e7b6..dc3f338a4 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonWebFluxConfiguration.java @@ -1,6 +1,5 @@ package org.hswebframework.web.crud.web; -import io.r2dbc.spi.R2dbcDataIntegrityViolationException; import org.hswebframework.web.i18n.WebFluxLocaleFilter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -33,12 +32,6 @@ public class CommonWebFluxConfiguration { return new ResponseMessageWrapper(codecConfigurer.getWriters(), resolver, registry); } - @Bean - public R2dbcDataIntegrityViolationException r2dbcDataIntegrityViolationException(){ - return new R2dbcDataIntegrityViolationException(); - } - - @Bean public WebFilter localeWebFilter() { return new WebFluxLocaleFilter(); From 3416fd24d6388701b111418bc11da1aa48d24097 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 09:22:27 +0800 Subject: [PATCH 02/46] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E6=BA=AF=E6=BA=90=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/exception/I18nSupportException.java | 2 +- .../web/exception/TraceSourceException.java | 50 +++++++++++++++++++ .../web/validator/ValidatorUtils.java | 6 +-- 3 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 6213a36c8..21341a0e9 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -19,7 +19,7 @@ import java.util.Objects; */ @Getter @Setter(AccessLevel.PROTECTED) -public class I18nSupportException extends RuntimeException { +public class I18nSupportException extends TraceSourceException { /** * 消息code,在message.properties文件中定义的key diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java new file mode 100644 index 000000000..89174fa8e --- /dev/null +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java @@ -0,0 +1,50 @@ +package org.hswebframework.web.exception; + +import javax.annotation.Nullable; +import java.util.Optional; + +/** + * 支持溯源的异常,通过{@link TraceSourceException#withSource(Object) }来标识异常的源头. + * 在捕获异常的地方通过获取异常源来处理一些逻辑,比如判断是由哪条数据发生的错误等操作. + * + * @author zhouhao + * @since 4.0.15 + */ +public class TraceSourceException extends RuntimeException { + + private Object source; + + public TraceSourceException() { + + } + + public TraceSourceException(String message) { + super(message); + } + + public TraceSourceException(Throwable e) { + super(e); + } + + public TraceSourceException(String message, Throwable e) { + super(message, e); + } + + public Optional sourceOptional() { + return Optional.ofNullable(source); + } + + @Nullable + public Object getSource() { + return source; + } + + public TraceSourceException withSource(Object source) { + this.source = source; + return self(); + } + + protected TraceSourceException self() { + return this; + } +} diff --git a/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java index 3db2fad56..4c5a1a748 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/validator/ValidatorUtils.java @@ -38,7 +38,7 @@ public final class ValidatorUtils { public static T tryValidate(T bean, Class... group) { Set> violations = getValidator().validate(bean, group); if (!violations.isEmpty()) { - throw new ValidationException(violations); + throw new ValidationException(violations).withSource(bean); } return bean; @@ -47,7 +47,7 @@ public final class ValidatorUtils { public static T tryValidate(T bean, String property, Class... group) { Set> violations = getValidator().validateProperty(bean, property, group); if (!violations.isEmpty()) { - throw new ValidationException(violations); + throw new ValidationException(violations).withSource(bean); } return bean; @@ -56,7 +56,7 @@ public final class ValidatorUtils { public static void tryValidate(Class bean, String property, Object value, Class... group) { Set> violations = getValidator().validateValue(bean, property, value, group); if (!violations.isEmpty()) { - throw new ValidationException(violations); + throw new ValidationException(violations).withSource(value); } } From 1284a3ec21979824139fe67bcb05baa3e28020a5 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 14:02:34 +0800 Subject: [PATCH 03/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/exception/I18nSupportException.java | 26 ++++ .../web/exception/TraceSourceException.java | 117 +++++++++++++++++- 2 files changed, 139 insertions(+), 4 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java index 21341a0e9..2478ab72b 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/I18nSupportException.java @@ -5,6 +5,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import org.hswebframework.web.i18n.LocaleUtils; +import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; import java.util.Locale; @@ -70,4 +71,29 @@ public class I18nSupportException extends TraceSourceException { .currentReactive() .map(this::getLocalizedMessage); } + + public static String tryGetLocalizedMessage(Throwable error, Locale locale) { + if (error instanceof I18nSupportException) { + return ((I18nSupportException) error).getLocalizedMessage(locale); + } + String msg = error.getMessage(); + + if (!StringUtils.hasText(msg)) { + msg = "error." + error.getClass().getSimpleName(); + } + if (msg.contains(".")) { + return LocaleUtils.resolveMessage(msg, locale, msg); + } + return msg; + } + + public static String tryGetLocalizedMessage(Throwable error) { + return tryGetLocalizedMessage(error, LocaleUtils.current()); + } + + public static Mono tryGetLocalizedMessageReactive(Throwable error) { + return LocaleUtils + .currentReactive() + .map(locale -> tryGetLocalizedMessage(error, locale)); + } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java index 89174fa8e..28341cbbe 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java @@ -1,7 +1,14 @@ package org.hswebframework.web.exception; +import org.hswebframework.web.i18n.LocaleUtils; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Mono; +import reactor.util.context.Context; + import javax.annotation.Nullable; +import java.util.Locale; import java.util.Optional; +import java.util.function.Function; /** * 支持溯源的异常,通过{@link TraceSourceException#withSource(Object) }来标识异常的源头. @@ -12,6 +19,11 @@ import java.util.Optional; */ public class TraceSourceException extends RuntimeException { + private static final String deepTraceKey = TraceSourceException.class.getName() + "_deep"; + private static final Context deepTraceContext = Context.of(deepTraceKey, true); + + private String operation; + private Object source; public TraceSourceException() { @@ -30,21 +42,118 @@ public class TraceSourceException extends RuntimeException { super(message, e); } - public Optional sourceOptional() { - return Optional.ofNullable(source); - } - @Nullable public Object getSource() { return source; } + @Nullable + public String getOperation() { + return operation; + } + public TraceSourceException withSource(Object source) { this.source = source; return self(); } + public TraceSourceException withSource(String operation, Object source) { + this.operation = operation; + this.source = source; + return self(); + } + protected TraceSourceException self() { return this; } + + /** + * 深度溯源上下文,用来标识是否是深度溯源的异常.开启深度追踪后,会创建新的{@link TraceSourceException}对象. + * + * @return 上下文 + * @see reactor.core.publisher.Flux#subscriberContext(Context) + * @see Mono#subscriberContext(Context) + */ + public static Context deepTraceContext() { + return deepTraceContext; + } + + public static Function> transfer(Object source) { + return transfer(null, source); + } + + + /** + * 溯源异常转换器.通常配合{@link Mono#onErrorResume(Function)}使用. + *

+ * 转换逻辑: + *

+ * 1. 如果捕获的异常不是TraceSourceException,则直接创建新的TraceSourceException并返回. + *

+ * 2. 如果捕获的异常是TraceSourceException,并且上下文没有指定{@link TraceSourceException#deepTraceContext()}, + * 则修改捕获的TraceSourceException异常中的source.如果上下文中指定了{@link TraceSourceException#deepTraceContext()} + * 则创建新的TraceSourceException + * + *

{@code
+     *
+     *  doSomething()
+     *  .onErrorResume(TraceSourceException.transfer(data))
+     *
+     * }
+ * + * @param operation 操作名称 + * @param source 源 + * @param 泛型 + * @return 转换器 + * @see reactor.core.publisher.Flux#onErrorResume(Function) + * @see Mono#onErrorResume(Function) + */ + public static Function> transfer(String operation, Object source) { + if (source == null && operation == null) { + return Mono::error; + } + return err -> { + if (err instanceof TraceSourceException) { + return Mono + .deferWithContext(ctx -> { + if (ctx.hasKey(deepTraceKey)) { + return Mono.error(new TraceSourceException(err).withSource(operation,source)); + } else { + return Mono.error(((TraceSourceException) err).withSource(operation,source)); + } + }); + } + return Mono.error(new TraceSourceException(err).withSource(operation,source)); + }; + } + + public static Object tryGetSource(Throwable err) { + if (err instanceof TraceSourceException) { + return ((TraceSourceException) err).getSource(); + } + return null; + } + + public static String tryGetOperation(Throwable err) { + if (err instanceof TraceSourceException) { + return ((TraceSourceException) err).getOperation(); + } + return null; + } + + public static String tryGetOperationLocalized(Throwable err, Locale locale) { + String opt = tryGetOperation(err); + return StringUtils.hasText(opt) ? LocaleUtils.resolveMessage(opt, locale, opt) : opt; + } + + public static Mono tryGetOperationLocalizedReactive(Throwable err) { + return LocaleUtils + .currentReactive() + .handle((locale, sink) -> { + String opt = tryGetOperationLocalized(err, locale); + if (opt != null) { + sink.next(opt); + } + }); + } } From 1a707a29eb0520f5f9db3ab3d1659f71e9515c30 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 15:18:25 +0800 Subject: [PATCH 04/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic/aop/AopAuthorizingController.java | 6 +++--- .../define/DefaultBasicAuthorizeDefinition.java | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java index d1d59ba53..23171ebd2 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/aop/AopAuthorizingController.java @@ -64,7 +64,8 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor AuthorizingContext context, Supplier> invoker) { - return Authentication.currentReactive() + return Authentication + .currentReactive() .switchIfEmpty(Mono.error(UnAuthorizedException::new)) .flatMapMany(auth -> { context.setAuthentication(auth); @@ -133,8 +134,7 @@ public class AopAuthorizingController extends StaticMethodMatcherPointcutAdvisor context.setAuthentication(authentication); isControl = true; - Phased dataAccessPhased = null; - dataAccessPhased = definition.getResources().getPhased(); + Phased dataAccessPhased = definition.getResources().getPhased(); if (definition.getPhased() == Phased.before) { //RDAC before authorizingHandler.handRBAC(context); diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java index d5c556493..dd334acf8 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/define/DefaultBasicAuthorizeDefinition.java @@ -38,7 +38,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { private String message = "error.access_denied"; - private Phased phased; + private Phased phased = Phased.before; @Override public boolean isEmpty() { @@ -65,6 +65,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { getResources().getResources().clear(); getDimensions().getDimensions().clear(); } + setPhased(ann.phased()); getResources().setPhased(ann.phased()); for (Resource resource : ann.resources()) { putAnnotation(resource); @@ -97,6 +98,8 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { putAnnotation(resource, action); } resource.setGroup(new ArrayList<>(Arrays.asList(ann.group()))); + setPhased(ann.phased()); + getResources().setPhased(ann.phased()); resources.addResource(resource, ann.merge()); } @@ -132,8 +135,8 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { return; } definition.getDataAccess() - .getDataAccessTypes() - .add(typeDefinition); + .getDataAccessTypes() + .add(typeDefinition); } public void putAnnotation(ResourceActionDefinition definition, DataAccessType dataAccessType) { @@ -147,8 +150,8 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { typeDefinition.setConfiguration(dataAccessType.configuration()); typeDefinition.setDescription(String.join("\n", dataAccessType.description())); definition.getDataAccess() - .getDataAccessTypes() - .add(typeDefinition); + .getDataAccessTypes() + .add(typeDefinition); } } From 69ab5f632d56cb71bbbba4fc412453068a7bdc02 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 3 Aug 2022 20:01:26 +0800 Subject: [PATCH 05/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=BB=A5=E5=8F=8A=E6=9D=83=E9=99=90=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../events/AuthorizationInitializeEvent.java | 5 +- .../simple/SimpleAuthentication.java | 18 ++-- ...activeAuthenticationInitializeService.java | 88 +++++++++++-------- 3 files changed, 67 insertions(+), 44 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java index 6144f6c5f..93f9bb261 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationInitializeEvent.java @@ -2,11 +2,14 @@ package org.hswebframework.web.authorization.events; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.Setter; import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.event.DefaultAsyncEvent; @Getter +@Setter @AllArgsConstructor -public class AuthorizationInitializeEvent { +public class AuthorizationInitializeEvent extends DefaultAsyncEvent { private Authentication authentication; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index 8d8ef7e7d..720e20c56 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -58,10 +58,16 @@ public class SimpleAuthentication implements Authentication { } public SimpleAuthentication merge(Authentication authentication) { - Map mePermissionGroup = permissions.stream() + Map mePermissionGroup = permissions + .stream() .collect(Collectors.toMap(Permission::getId, Function.identity())); - user = authentication.getUser(); + + if (authentication.getUser() != null) { + user = authentication.getUser(); + } + attributes.putAll(authentication.getAttributes()); + for (Permission permission : authentication.getPermissions()) { Permission me = mePermissionGroup.get(permission.getId()); if (me == null) { @@ -88,10 +94,10 @@ public class SimpleAuthentication implements Authentication { authentication.setUser(user); authentication.setDimensions(dimensions.stream().filter(dimension).collect(Collectors.toList())); authentication.setPermissions(permissions - .stream() - .map(permission -> permission.copy(action -> permissionFilter.test(permission, action), conf -> true)) - .filter(per -> !per.getActions().isEmpty()) - .collect(Collectors.toList()) + .stream() + .map(permission -> permission.copy(action -> permissionFilter.test(permission, action), conf -> true)) + .filter(per -> !per.getActions().isEmpty()) + .collect(Collectors.toList()) ); return authentication; } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java index b3fc14096..44d431e14 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java @@ -10,6 +10,7 @@ import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeServ import org.hswebframework.web.authorization.access.DataAccessConfig; import org.hswebframework.web.authorization.access.DataAccessType; import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory; +import org.hswebframework.web.authorization.events.AuthorizationInitializeEvent; import org.hswebframework.web.authorization.simple.SimpleAuthentication; import org.hswebframework.web.authorization.simple.SimplePermission; import org.hswebframework.web.authorization.simple.SimpleUser; @@ -21,6 +22,7 @@ import org.hswebframework.web.system.authorization.api.entity.PermissionEntity; import org.hswebframework.web.system.authorization.api.entity.UserEntity; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.util.StringUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -48,6 +50,9 @@ public class DefaultReactiveAuthenticationInitializeService @Autowired(required = false) private List dimensionProviders = new ArrayList<>(); + @Autowired + private ApplicationEventPublisher eventPublisher; + @Override public Mono initUserAuthorization(String userId) { return doInit(userService.findById(userId)); @@ -58,17 +63,23 @@ public class DefaultReactiveAuthenticationInitializeService return userEntityMono.flatMap(user -> { SimpleAuthentication authentication = new SimpleAuthentication(); authentication.setUser(SimpleUser - .builder() - .id(user.getId()) - .name(user.getName()) - .username(user.getUsername()) - .userType(user.getType()) - .build()); + .builder() + .id(user.getId()) + .name(user.getName()) + .username(user.getUsername()) + .userType(user.getType()) + .build()); return initPermission(authentication) .switchIfEmpty(Mono.just(authentication)) .onErrorResume(err -> { log.warn(err.getMessage(), err); return Mono.just(authentication); + }) + .flatMap(auth -> { + AuthorizationInitializeEvent event = new AuthorizationInitializeEvent(auth); + return event + .publish(eventPublisher) + .then(Mono.fromSupplier(event::getAuthentication)); }); }); @@ -76,31 +87,31 @@ public class DefaultReactiveAuthenticationInitializeService protected Flux getSettings(List dimensions) { return Flux.fromIterable(dimensions) - .filter(dimension -> dimension.getType() != null) - .groupBy(d -> d.getType().getId(), (Function) Dimension::getId) - .flatMap(group -> - group.collectList() - .flatMapMany(list -> settingRepository - .createQuery() - .where(AuthorizationSettingEntity::getState, 1) - .and(AuthorizationSettingEntity::getDimensionType, group.key()) - .in(AuthorizationSettingEntity::getDimensionTarget, list) - .fetch())); + .filter(dimension -> dimension.getType() != null) + .groupBy(d -> d.getType().getId(), (Function) Dimension::getId) + .flatMap(group -> + group.collectList() + .flatMapMany(list -> settingRepository + .createQuery() + .where(AuthorizationSettingEntity::getState, 1) + .and(AuthorizationSettingEntity::getDimensionType, group.key()) + .in(AuthorizationSettingEntity::getDimensionTarget, list) + .fetch())); } protected Mono initPermission(SimpleAuthentication authentication) { return Flux.fromIterable(dimensionProviders) - .flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId())) - .cast(Dimension.class) - .collectList() - .doOnNext(authentication::setDimensions) - .flatMap(allDimension -> - Mono.zip( - getAllPermission() - , getSettings(allDimension) - .collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)) - , (_p, _s) -> handlePermission(authentication, allDimension, _p, _s) - )); + .flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId())) + .cast(Dimension.class) + .collectList() + .doOnNext(authentication::setDimensions) + .flatMap(allDimension -> + Mono.zip( + getAllPermission() + , getSettings(allDimension) + .collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)) + , (_p, _s) -> handlePermission(authentication, allDimension, _p, _s) + )); } @@ -134,16 +145,19 @@ public class DefaultReactiveAuthenticationInitializeService if (permissionSetting.getDataAccesses() != null) { permissionSetting.getDataAccesses() - .stream() - .map(conf -> { - DataAccessConfig config = builderFactory.create().fromMap(conf.toMap()).build(); - if (config == null) { - log.warn("unsupported data access:{}", conf.toMap()); - } - return config; - }) - .filter(Objects::nonNull) - .forEach(configs::add); + .stream() + .map(conf -> { + DataAccessConfig config = builderFactory + .create() + .fromMap(conf.toMap()) + .build(); + if (config == null) { + log.warn("unsupported data access:{}", conf.toMap()); + } + return config; + }) + .filter(Objects::nonNull) + .forEach(configs::add); } if (CollectionUtils.isNotEmpty(permissionSetting.getActions())) { permission.getActions().addAll(permissionSetting.getActions()); From c5b9adabbea1a8db161607f02ea18520d0383a03 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 10 Aug 2022 17:27:53 +0800 Subject: [PATCH 06/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/events/ValidateEventListener.java | 7 +- .../web/exception/TraceSourceException.java | 2 +- .../hswebframework/web/i18n/LocaleUtils.java | 116 ++++++++++++++++-- .../web/i18n/WebFluxLocaleFilter.java | 1 + .../web/i18n/LocaleUtilsTest.java | 32 ++++- .../jackson/CustomJackson2JsonDecoder.java | 45 +++---- .../jackson/CustomJackson2jsonEncoder.java | 111 +++++++---------- 7 files changed, 206 insertions(+), 108 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index be7e1fb00..342dc9e92 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -35,9 +35,10 @@ public class ValidateEventListener implements EventListener { resultHolder .ifPresent(holder -> holder .invoke(LocaleUtils - .currentReactive() - .doOnNext(locale -> LocaleUtils.doWith(locale, (l) -> tryValidate(type, context))) - .then() + .doInReactive(() -> { + tryValidate(type, context); + return null; + }) )); } else { tryValidate(type, context); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java index 28341cbbe..30ab58049 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/exception/TraceSourceException.java @@ -35,7 +35,7 @@ public class TraceSourceException extends RuntimeException { } public TraceSourceException(Throwable e) { - super(e); + super(e.getMessage(),e); } public TraceSourceException(String message, Throwable e) { diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index d3c66ade3..156d4a989 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -1,15 +1,17 @@ package org.hswebframework.web.i18n; +import lombok.AllArgsConstructor; import org.hswebframework.web.exception.I18nSupportException; import org.reactivestreams.Publisher; +import org.reactivestreams.Subscription; import org.springframework.context.MessageSource; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.publisher.Signal; -import reactor.core.publisher.SignalType; +import reactor.core.CoreSubscriber; +import reactor.core.publisher.*; import reactor.util.context.Context; +import javax.annotation.Nonnull; import java.util.Locale; +import java.util.concurrent.Callable; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -23,7 +25,6 @@ import java.util.function.Function; *
  • {@link LocaleUtils#current()}
  • *
  • {@link LocaleUtils#currentReactive()}
  • *
  • {@link LocaleUtils#resolveMessageReactive(String, Object...)}
  • - *
  • {@link LocaleUtils#doOnNext(BiConsumer)}
  • * * * @author zhouhao @@ -63,11 +64,12 @@ public final class LocaleUtils { * @return 返回值 */ public static R doWith(T data, Locale locale, BiFunction mapper) { + Locale old = CONTEXT_THREAD_LOCAL.get(); try { CONTEXT_THREAD_LOCAL.set(locale); return mapper.apply(data, locale); } finally { - CONTEXT_THREAD_LOCAL.remove(); + CONTEXT_THREAD_LOCAL.set(old); } } @@ -78,11 +80,12 @@ public final class LocaleUtils { * @param consumer 任务 */ public static void doWith(Locale locale, Consumer consumer) { + Locale old = CONTEXT_THREAD_LOCAL.get(); try { CONTEXT_THREAD_LOCAL.set(locale); consumer.accept(locale); } finally { - CONTEXT_THREAD_LOCAL.remove(); + CONTEXT_THREAD_LOCAL.set(old); } } @@ -112,6 +115,23 @@ public final class LocaleUtils { .subscriberContext() .map(ctx -> ctx.getOrDefault(Locale.class, DEFAULT_LOCALE)); } + public static Mono doInReactive(Callable call) { + return currentReactive() + .handle((locale, sink) -> { + Locale old = CONTEXT_THREAD_LOCAL.get(); + try { + CONTEXT_THREAD_LOCAL.set(locale); + T data = call.call(); + if (data != null) { + sink.next(data); + } + } catch (Throwable e) { + sink.error(e); + } finally { + CONTEXT_THREAD_LOCAL.set(old); + } + }); + } /** * 响应式方式解析出异常的区域消息,并进行结果转换. @@ -450,4 +470,86 @@ public final class LocaleUtils { return doOn(SignalType.ON_ERROR, (s, l) -> operation.accept(s.getThrowable(), l)); } + public static Flux transform(Flux flux) { + return new LocaleFlux<>(flux); + } + + public static Mono transform(Mono mono) { + return new LocaleMono<>(mono); + } + + @AllArgsConstructor + static class LocaleMono extends Mono { + private final Mono source; + + @Override + public void subscribe(@Nonnull CoreSubscriber actual) { + doWith(actual, + actual.currentContext().getOrDefault(Locale.class, DEFAULT_LOCALE), + (a, l) -> { + source.subscribe( + new LocaleSwitchSubscriber<>(a) + ); + return null; + } + ); + } + } + + @AllArgsConstructor + static class LocaleFlux extends Flux { + private final Flux source; + + @Override + public void subscribe(@Nonnull CoreSubscriber actual) { + source.subscribe( + new LocaleSwitchSubscriber<>(actual) + ); + } + } + + @AllArgsConstructor + static class LocaleSwitchSubscriber extends BaseSubscriber { + private final CoreSubscriber actual; + + @Override + @Nonnull + public Context currentContext() { + return actual + .currentContext(); + } + + @Override + protected void hookOnSubscribe(@Nonnull Subscription subscription) { + actual.onSubscribe(this); + } + + private Locale current() { + return currentContext() + .getOrDefault(Locale.class, DEFAULT_LOCALE); + } + + @Override + protected void hookOnComplete() { + doWith(current(), (l) -> actual.onComplete()); + } + + @Override + protected void hookOnError(@Nonnull Throwable error) { + + doWith(error, current(), (v, l) -> { + actual.onError(v); + return null; + }); + } + + @Override + protected void hookOnNext(@Nonnull T value) { + + doWith(value, current(), (v, l) -> { + actual.onNext(v); + return null; + }); + } + } } diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java index 748d7faee..61a34e1d6 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/WebFluxLocaleFilter.java @@ -15,6 +15,7 @@ public class WebFluxLocaleFilter implements WebFilter { public Mono filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) { return chain .filter(exchange) + .as(LocaleUtils::transform) .subscriberContext(LocaleUtils.useLocale(getLocaleContext(exchange))); } diff --git a/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java b/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java index e68469bf4..0ce7042a2 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/i18n/LocaleUtilsTest.java @@ -2,6 +2,8 @@ package org.hswebframework.web.i18n; import org.junit.Test; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import java.util.Locale; @@ -11,15 +13,35 @@ public class LocaleUtilsTest { @Test - public void testOnNext() { + public void testFlux() { Flux.just(1) - .as(LocaleUtils.doOnNext((i, l) -> { + .as(LocaleUtils::transform) + .doOnNext(i -> { assertEquals(i.intValue(), 1); - assertEquals(l, Locale.CHINA); - })) - .subscriberContext(LocaleUtils.useLocale(Locale.CHINA)) + assertEquals(LocaleUtils.current(), Locale.ENGLISH); + }) + .subscriberContext(LocaleUtils.useLocale(Locale.ENGLISH)) .blockLast(); } + @Test + public void testMono() { + Mono.just(1) + .doOnNext(i -> { + assertEquals(i.intValue(), 1); + assertEquals(LocaleUtils.current(), Locale.ENGLISH); + }) + .as(LocaleUtils::transform) + .subscriberContext(LocaleUtils.useLocale(Locale.ENGLISH)) + .block(); + + LocaleUtils + .doInReactive(()->{ + assertEquals(LocaleUtils.current(), Locale.ENGLISH); + return null; + }) + .subscriberContext(LocaleUtils.useLocale(Locale.ENGLISH)) + .block(); + } } \ No newline at end of file diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java index cbf0100b8..454933464 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java @@ -28,12 +28,10 @@ import org.springframework.util.MimeType; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import javax.annotation.Nonnull; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.Collection; import java.util.List; import java.util.Map; @@ -70,23 +68,19 @@ public class CustomJackson2JsonDecoder extends Jackson2CodecSupport implements H ObjectReader reader = getObjectReader(elementType, hints); - return LocaleUtils - .currentReactive() - .flatMapMany(locale -> tokens - .handle((tokenBuffer, sink) -> { - LocaleUtils.doWith(locale, l -> { - try { - Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper())); - logValue(value, hints); - if (value != null) { - sink.next(value); - } - } catch (IOException ex) { - sink.error(processException(ex)); - } - }); - - })); + return tokens + .as(LocaleUtils::transform) + .handle((tokenBuffer, sink) -> { + try { + Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper())); + logValue(value, hints); + if (value != null) { + sink.next(value); + } + } catch (IOException ex) { + sink.error(processException(ex)); + } + }); } @Override @@ -94,15 +88,10 @@ public class CustomJackson2JsonDecoder extends Jackson2CodecSupport implements H public Mono decodeToMono(@NonNull Publisher input, @NonNull ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map hints) { - return LocaleUtils - .currentReactive() - .flatMap(locale -> DataBufferUtils - .join(input) - .map(dataBuffer -> LocaleUtils - .doWith(dataBuffer, - locale, - (buf, l) -> decode(buf, elementType, mimeType, hints))) - ); + return DataBufferUtils + .join(input) + .as(LocaleUtils::transform) + .map(dataBuffer -> decode(dataBuffer, elementType, mimeType, hints)); } @Override diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java index a999fb9f6..27c42a42d 100644 --- a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2jsonEncoder.java @@ -116,72 +116,55 @@ public class CustomJackson2jsonEncoder extends Jackson2CodecSupport implements H Assert.notNull(bufferFactory, "'bufferFactory' must not be null"); Assert.notNull(elementType, "'elementType' must not be null"); - return LocaleUtils - .currentReactive() - .flatMapMany(locale -> { - if (inputStream instanceof Mono) { - return Mono.from(inputStream) - .map(value -> LocaleUtils - .doWith(value, locale, - ((val, loc) -> - encodeValue(val, bufferFactory, elementType, mimeType, hints) - ) - )) - .flux(); - } else { - byte[] separator = streamSeparator(mimeType); - if (separator != null) { // streaming - try { - ObjectWriter writer = createObjectWriter(elementType, mimeType, hints); - ByteArrayBuilder byteBuilder = new ByteArrayBuilder(writer - .getFactory() - ._getBufferRecycler()); - JsonEncoding encoding = getJsonEncoding(mimeType); - JsonGenerator generator = getObjectMapper() - .getFactory() - .createGenerator(byteBuilder, encoding); - SequenceWriter sequenceWriter = writer.writeValues(generator); + if (inputStream instanceof Mono) { + return Mono.from(inputStream) + .as(LocaleUtils::transform) + .map(value -> encodeValue(value, bufferFactory, elementType, mimeType, hints)) + .flux(); + } else { + byte[] separator = streamSeparator(mimeType); + if (separator != null) { // streaming + try { + ObjectWriter writer = createObjectWriter(elementType, mimeType, hints); + ByteArrayBuilder byteBuilder = new ByteArrayBuilder(writer + .getFactory() + ._getBufferRecycler()); + JsonEncoding encoding = getJsonEncoding(mimeType); + JsonGenerator generator = getObjectMapper() + .getFactory() + .createGenerator(byteBuilder, encoding); + SequenceWriter sequenceWriter = writer.writeValues(generator); - return Flux - .from(inputStream) - .map(value -> LocaleUtils - .doWith(value, - locale, - ((val, loc) -> this - .encodeStreamingValue(val, - bufferFactory, - hints, - sequenceWriter, - byteBuilder, - separator) - ) - )) - .doAfterTerminate(() -> { - try { - byteBuilder.release(); - generator.close(); - } catch (IOException ex) { - logger.error("Could not close Encoder resources", ex); - } - }); - } catch (IOException ex) { - return Flux.error(ex); - } - } else { // non-streaming - ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); - return Flux.from(inputStream) - .collectList() - .map(value -> LocaleUtils - .doWith(value, locale, - ((val, loc) -> - encodeValue(val, bufferFactory, listType, mimeType, hints) - ) - )) - .flux(); - } + return Flux + .from(inputStream) + .as(LocaleUtils::transform) + .map(value -> this.encodeStreamingValue(value, + bufferFactory, + hints, + sequenceWriter, + byteBuilder, + separator)) + .doAfterTerminate(() -> { + try { + byteBuilder.release(); + generator.close(); + } catch (IOException ex) { + logger.error("Could not close Encoder resources", ex); + } + }); + } catch (IOException ex) { + return Flux.error(ex); + } + } else { // non-streaming + ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); + return Flux.from(inputStream) + .collectList() + .as(LocaleUtils::transform) + .map(value -> encodeValue(value, bufferFactory, listType, mimeType, hints)) + .flux(); + } - } - }); + } } @Override From fa3b4dded9d33072e7053e4693d334a98196ce28 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 10 Aug 2022 17:40:46 +0800 Subject: [PATCH 07/46] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/hswebframework/web/i18n/LocaleUtils.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java index 156d4a989..44c524ae2 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/i18n/LocaleUtils.java @@ -502,8 +502,14 @@ public final class LocaleUtils { @Override public void subscribe(@Nonnull CoreSubscriber actual) { - source.subscribe( - new LocaleSwitchSubscriber<>(actual) + doWith(actual, + actual.currentContext().getOrDefault(Locale.class, DEFAULT_LOCALE), + (a, l) -> { + source.subscribe( + new LocaleSwitchSubscriber<>(a) + ); + return null; + } ); } } From 03c47f12283d230caf21122730ed1add2cac85f0 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 17 Aug 2022 20:38:29 +0800 Subject: [PATCH 08/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/SimpleAuthentication.java | 8 +- .../AuthorizingHandlerAutoConfiguration.java | 6 ++ .../basic/web/BearerTokenParser.java | 22 ++++++ .../basic/web/DefaultUserTokenGenPar.java | 12 +-- .../server/OAuth2ServerAutoConfiguration.java | 23 +++--- .../code/DefaultAuthorizationCodeGranter.java | 5 +- .../server/impl/RedisAccessTokenManager.java | 74 ++++++++++++++----- .../oauth2/server/utils/OAuth2ScopeUtils.java | 11 ++- .../authorization/api/entity/UserEntity.java | 12 ++- .../service/reactive/ReactiveUserService.java | 2 + ...AuthorizationServiceAutoConfiguration.java | 8 +- ...activeAuthenticationInitializeService.java | 4 +- .../service/DefaultReactiveUserService.java | 12 ++- 13 files changed, 147 insertions(+), 52 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index 720e20c56..e318c6c19 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -78,7 +78,6 @@ public class SimpleAuthentication implements Authentication { me.getDataAccesses().addAll(permission.getDataAccesses()); } - for (Dimension dimension : authentication.getDimensions()) { if (!getDimension(dimension.getType(), dimension.getId()).isPresent()) { dimensions.add(dimension); @@ -91,7 +90,6 @@ public class SimpleAuthentication implements Authentication { public Authentication copy(BiPredicate permissionFilter, Predicate dimension) { SimpleAuthentication authentication = new SimpleAuthentication(); - authentication.setUser(user); authentication.setDimensions(dimensions.stream().filter(dimension).collect(Collectors.toList())); authentication.setPermissions(permissions .stream() @@ -99,6 +97,12 @@ public class SimpleAuthentication implements Authentication { .filter(per -> !per.getActions().isEmpty()) .collect(Collectors.toList()) ); + authentication.setUser(user); return authentication; } + + public void setUser(User user) { + this.user = user; + dimensions.add(user); + } } diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java index 50e4510a9..3ba9465d1 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java @@ -145,6 +145,12 @@ public class AuthorizingHandlerAutoConfiguration { return new ReactiveUserTokenController(); } + @Bean + @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) + public BearerTokenParser bearerTokenParser() { + return new BearerTokenParser(); + } + @Configuration public static class DataAccessHandlerProcessor implements BeanPostProcessor { diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java new file mode 100644 index 000000000..d7c49d176 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/BearerTokenParser.java @@ -0,0 +1,22 @@ +package org.hswebframework.web.authorization.basic.web; + +import org.hswebframework.web.authorization.token.ParsedToken; +import org.springframework.http.HttpHeaders; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +public class BearerTokenParser implements ReactiveUserTokenParser { + @Override + public Mono parseToken(ServerWebExchange exchange) { + + String token = exchange + .getRequest() + .getHeaders() + .getFirst(HttpHeaders.AUTHORIZATION); + + if (token != null && token.startsWith("Bearer ")) { + return Mono.just(ParsedToken.of("bearer", token.substring(7))); + } + return Mono.empty(); + } +} diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java index 0e4c1810f..b1948ef42 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/DefaultUserTokenGenPar.java @@ -62,16 +62,6 @@ public class DefaultUserTokenGenPar implements ReactiveUserTokenGenerator, React if (token == null) { return Mono.empty(); } - return Mono.just(new ParsedToken() { - @Override - public String getToken() { - return token; - } - - @Override - public String getType() { - return getTokenType(); - } - }); + return Mono.just(ParsedToken.of(getTokenType(),token)); } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java index 6003a593f..842e21125 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java @@ -3,6 +3,8 @@ package org.hswebframework.web.oauth2.server; import org.hswebframework.web.authorization.ReactiveAuthenticationHolder; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; import org.hswebframework.web.authorization.basic.web.ReactiveUserTokenParser; +import org.hswebframework.web.authorization.token.UserToken; +import org.hswebframework.web.authorization.token.UserTokenManager; import org.hswebframework.web.oauth2.server.auth.ReactiveOAuth2AccessTokenParser; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeGranter; import org.hswebframework.web.oauth2.server.code.DefaultAuthorizationCodeGranter; @@ -22,6 +24,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; +import org.springframework.data.redis.core.ReactiveRedisOperations; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(OAuth2Properties.class) @@ -32,13 +35,13 @@ public class OAuth2ServerAutoConfiguration { @ConditionalOnClass(ReactiveUserTokenParser.class) static class ReactiveOAuth2AccessTokenParserConfiguration { - @Bean - @ConditionalOnBean(AccessTokenManager.class) - public ReactiveOAuth2AccessTokenParser reactiveOAuth2AccessTokenParser(AccessTokenManager accessTokenManager) { - ReactiveOAuth2AccessTokenParser parser = new ReactiveOAuth2AccessTokenParser(accessTokenManager); - ReactiveAuthenticationHolder.addSupplier(parser); - return parser; - } +// @Bean +// @ConditionalOnBean(AccessTokenManager.class) +// public ReactiveOAuth2AccessTokenParser reactiveOAuth2AccessTokenParser(AccessTokenManager accessTokenManager) { +// ReactiveOAuth2AccessTokenParser parser = new ReactiveOAuth2AccessTokenParser(accessTokenManager); +// ReactiveAuthenticationHolder.addSupplier(parser); +// return parser; +// } } @Configuration(proxyBeanMethods = false) @@ -48,9 +51,11 @@ public class OAuth2ServerAutoConfiguration { @Bean @ConditionalOnMissingBean - public AccessTokenManager accessTokenManager(ReactiveRedisConnectionFactory redisConnectionFactory, + public AccessTokenManager accessTokenManager(ReactiveRedisOperations redis, + UserTokenManager tokenManager, OAuth2Properties properties) { - RedisAccessTokenManager manager = new RedisAccessTokenManager(redisConnectionFactory); + @SuppressWarnings("all") + RedisAccessTokenManager manager = new RedisAccessTokenManager((ReactiveRedisOperations) redis, tokenManager); manager.setTokenExpireIn((int) properties.getTokenExpireIn().getSeconds()); manager.setRefreshExpireIn((int) properties.getRefreshTokenIn().getSeconds()); return manager; diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java index c3b53cabd..472cedfa0 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java @@ -48,9 +48,12 @@ public class DefaultAuthorizationCodeGranter implements AuthorizationCodeGranter request.getParameter(OAuth2Constants.scope).map(String::valueOf).ifPresent(codeCache::setScope); codeCache.setCode(code); codeCache.setClientId(client.getClientId()); + ScopePredicate permissionPredicate = OAuth2ScopeUtils.createScopePredicate(codeCache.getScope()); - codeCache.setAuthentication(authentication.copy((permission, action) -> permissionPredicate.test(permission.getId(), action), dimension -> true)); + codeCache.setAuthentication(authentication.copy( + (permission, action) -> permissionPredicate.test(permission.getId(), action), + dimension -> permissionPredicate.test(dimension.getType().getId(), dimension.getId()))); return redis diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index e6a0a0ac6..fe1e9b39b 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -4,6 +4,9 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.codec.digest.DigestUtils; import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.token.AuthenticationUserToken; +import org.hswebframework.web.authorization.token.UserTokenManager; +import org.hswebframework.web.authorization.token.redis.RedisUserTokenManager; import org.hswebframework.web.oauth2.ErrorType; import org.hswebframework.web.oauth2.OAuth2Exception; import org.hswebframework.web.oauth2.server.AccessToken; @@ -13,6 +16,7 @@ import org.springframework.data.redis.core.ReactiveRedisOperations; import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializer; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; @@ -22,6 +26,8 @@ public class RedisAccessTokenManager implements AccessTokenManager { private final ReactiveRedisOperations tokenRedis; + private final UserTokenManager userTokenManager; + @Getter @Setter private int tokenExpireIn = 7200;//2小时 @@ -30,29 +36,32 @@ public class RedisAccessTokenManager implements AccessTokenManager { @Setter private int refreshExpireIn = 2592000; //30天 - public RedisAccessTokenManager(ReactiveRedisOperations tokenRedis) { + public RedisAccessTokenManager(ReactiveRedisOperations tokenRedis, + UserTokenManager userTokenManager) { this.tokenRedis = tokenRedis; + this.userTokenManager = userTokenManager; } @SuppressWarnings("all") public RedisAccessTokenManager(ReactiveRedisConnectionFactory connectionFactory) { - this(new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext + ReactiveRedisTemplate redis = new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext .newSerializationContext() .key((RedisSerializer) RedisSerializer.string()) .value(RedisSerializer.java()) .hashKey(RedisSerializer.string()) .hashValue(RedisSerializer.java()) - .build() - )); + .build()); + this.tokenRedis = redis; + this.userTokenManager = new RedisUserTokenManager(redis); } + @Override public Mono getAuthenticationByToken(String accessToken) { - - return tokenRedis - .opsForValue() - .get(createTokenRedisKey(accessToken)) - .map(RedisAccessToken::getAuthentication); + return userTokenManager + .getByToken(accessToken) + .filter(token -> token instanceof AuthenticationUserToken) + .map(t -> ((AuthenticationUserToken) t).getAuthentication()); } private String createTokenRedisKey(String token) { @@ -75,12 +84,36 @@ public class RedisAccessTokenManager implements AccessTokenManager { return storeToken(accessToken).thenReturn(accessToken); } + private Mono storeAuthToken(RedisAccessToken token) { + if (token.isSingleton()) { + return userTokenManager + .signIn(token.getAccessToken(), + "oauth2", + token.getAuthentication().getUser().getId(), + tokenExpireIn * 1000L) + .then(); + } else { + return userTokenManager + .signIn(token.getAccessToken(), + "oauth2", + token.getAuthentication().getUser().getId(), + tokenExpireIn * 1000L, + token.getAuthentication()) + .then(); + } + } + private Mono storeToken(RedisAccessToken token) { - return Mono - .zip( - tokenRedis.opsForValue().set(createTokenRedisKey(token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), - tokenRedis.opsForValue().set(createRefreshTokenRedisKey(token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn)) - ).then(); + + return Flux + .merge(storeAuthToken(token), + tokenRedis + .opsForValue() + .set(createTokenRedisKey(token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), + tokenRedis + .opsForValue() + .set(createRefreshTokenRedisKey(token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn))) + .then(); } private Mono doCreateSingletonAccessToken(String clientId, Authentication authentication) { @@ -129,10 +162,15 @@ public class RedisAccessTokenManager implements AccessTokenManager { .as(result -> { // 单例token if (token.isSingleton()) { - return tokenRedis - .opsForValue() - .set(createSingletonTokenRedisKey(clientId), token, Duration.ofSeconds(tokenExpireIn)) - .then(result); + return userTokenManager + .signOutByToken(token.getAccessToken()) + .then( + tokenRedis + .opsForValue() + .set(createSingletonTokenRedisKey(clientId), token, Duration.ofSeconds(tokenExpireIn)) + .then(result) + ) + ; } return result; }) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java index 4ac30fff0..40806f974 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/utils/OAuth2ScopeUtils.java @@ -6,6 +6,10 @@ import org.springframework.util.StringUtils; import java.util.*; /** + *
    {@code
    + *   role:* user:* device-manager:*
    + * }
    + * * @author zhouhao * @since 4.0.8 */ @@ -23,10 +27,13 @@ public class OAuth2ScopeUtils { Set acts = actions.computeIfAbsent(per, k -> new HashSet<>()); acts.addAll(Arrays.asList(permissions).subList(1, permissions.length)); } - + //全部授权 + if (actions.containsKey("*")) { + return ((permission, action) -> true); + } return ((permission, action) -> Optional .ofNullable(actions.get(permission)) - .map(acts -> action.length == 0 || acts.containsAll(Arrays.asList(action))) + .map(acts -> action.length == 0 || acts.contains("*") || acts.containsAll(Arrays.asList(action))) .orElse(false)); } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java index d903669aa..2e831be27 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/UserEntity.java @@ -1,5 +1,7 @@ package org.hswebframework.web.system.authorization.api.entity; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.media.Schema; @@ -9,15 +11,18 @@ import org.apache.commons.codec.digest.DigestUtils; import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; import org.hswebframework.web.api.crud.entity.GenericEntity; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.api.crud.entity.RecordCreationEntity; import org.hswebframework.web.bean.ToString; import org.hswebframework.web.validator.CreateGroup; +import org.springframework.util.StringUtils; import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.Index; import javax.persistence.Table; import javax.validation.constraints.NotBlank; +import java.util.Objects; /** * 系统用户实体 @@ -85,7 +90,10 @@ public class UserEntity extends GenericEntity implements RecordCreationE return super.getId(); } - public void generateId(){ - setId(DigestUtils.md5Hex(username)); + public void generateId() { + if (StringUtils.hasText(getId())) { + return; + } + setId(DigestUtils.md5Hex(username)); } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java index d7d3ace6d..209196cde 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/service/reactive/ReactiveUserService.java @@ -29,6 +29,8 @@ public interface ReactiveUserService { */ Mono saveUser(Mono userEntity); + Mono addUser(UserEntity userEntity); + /** * 根据用户名查询用户实体,如果用户不存在则返回{@link Mono#empty()} * diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java index 2d80c4fba..47f501d6f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationServiceAutoConfiguration.java @@ -55,10 +55,10 @@ public class AuthorizationServiceAutoConfiguration { return new DefaultDimensionService(); } - @Bean - public UserDimensionProvider userPermissionDimensionProvider() { - return new UserDimensionProvider(); - } +// @Bean +// public UserDimensionProvider userPermissionDimensionProvider() { +// return new UserDimensionProvider(); +// } @Bean public DefaultDimensionUserService defaultDimensionUserService() { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java index 44d431e14..2cce5809b 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java @@ -69,8 +69,9 @@ public class DefaultReactiveAuthenticationInitializeService .username(user.getUsername()) .userType(user.getType()) .build()); + return initPermission(authentication) - .switchIfEmpty(Mono.just(authentication)) + .defaultIfEmpty(authentication) .onErrorResume(err -> { log.warn(err.getMessage(), err); return Mono.just(authentication); @@ -82,7 +83,6 @@ public class DefaultReactiveAuthenticationInitializeService .then(Mono.fromSupplier(event::getAuthentication)); }); }); - } protected Flux getSettings(List dimensions) { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java index b90247e24..7a730552a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveUserService.java @@ -24,6 +24,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import javax.validation.ValidationException; +import java.util.Objects; public class DefaultReactiveUserService extends GenericReactiveCrudService implements ReactiveUserService { @@ -61,10 +62,19 @@ public class DefaultReactiveUserService extends GenericReactiveCrudService doUpdate(userEntity)) - .switchIfEmpty(Mono.error(NotFoundException::new)); + .switchIfEmpty( + Objects.equals(userEntity.getId(),userEntity.getUsername()) ? + doAdd(userEntity) : + Mono.error(NotFoundException::new) + ); }).thenReturn(true); } + @Override + public Mono addUser(UserEntity userEntity) { + return doAdd(userEntity); + } + protected Mono doAdd(UserEntity userEntity) { return Mono From f728de139939a21f40a59fccead5bf4940233222 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 10:01:50 +0800 Subject: [PATCH 09/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E4=BC=98=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aop/ReactiveAopAccessLoggerSupport.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java index 76b5cf295..f7130b11d 100644 --- a/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java +++ b/hsweb-logging/hsweb-access-logging-aop/src/main/java/org/hswebframework/web/logging/aop/ReactiveAopAccessLoggerSupport.java @@ -39,7 +39,7 @@ import java.util.concurrent.atomic.AtomicReference; * @author zhouhao * @since 3.0 */ -public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutAdvisor implements WebFilter { +public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutAdvisor implements WebFilter{ @Autowired(required = false) private final List loggerParsers = new ArrayList<>(); @@ -58,9 +58,11 @@ public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutA AccessLoggerInfo info = createLogger(methodInterceptorHolder); Object response = methodInvocation.proceed(); if (response instanceof Mono) { - return wrapMonoResponse(((Mono) response), info); + return wrapMonoResponse(((Mono) response), info) + .subscriberContext(Context.of(AccessLoggerInfo.class, info)); } else if (response instanceof Flux) { - return wrapFluxResponse(((Flux) response), info); + return wrapFluxResponse(((Flux) response), info) + .subscriberContext(Context.of(AccessLoggerInfo.class, info)); } return response; }); @@ -183,7 +185,7 @@ public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutA @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE; + return Ordered.HIGHEST_PRECEDENCE; } @Override @@ -217,10 +219,12 @@ public class ReactiveAopAccessLoggerSupport extends StaticMethodMatcherPointcutA return info; } + @AllArgsConstructor @EqualsAndHashCode - private static class CacheKey{ + private static class CacheKey { private Class type; private Method method; } + } From ffb0e24acc29d05a2108d5caa5acdf1b230969c1 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 10:32:42 +0800 Subject: [PATCH 10/46] =?UTF-8?q?=E5=A2=9E=E5=8A=A0OAuth2GrantedEvent?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/oauth2/server/AccessTokenManager.java | 1 + .../server/OAuth2ServerAutoConfiguration.java | 9 +++-- .../code/DefaultAuthorizationCodeGranter.java | 34 ++++++++++++++----- .../DefaultClientCredentialGranter.java | 20 ++++++++++- .../server/event/OAuth2GrantedEvent.java | 32 +++++++++++++++++ .../server/impl/RedisAccessTokenManager.java | 10 ++++++ .../server/web/OAuth2AuthorizeController.java | 2 ++ .../DefaultAuthorizationCodeGranterTest.java | 3 +- 8 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java index e90793c6c..37b484e85 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java @@ -40,4 +40,5 @@ public interface AccessTokenManager { */ Mono refreshAccessToken(String clientId, String refreshToken); + Mono removeToken(String clientId,String token); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java index 842e21125..42f1a575c 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/OAuth2ServerAutoConfiguration.java @@ -21,6 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; @@ -64,15 +65,17 @@ public class OAuth2ServerAutoConfiguration { @Bean @ConditionalOnMissingBean public ClientCredentialGranter clientCredentialGranter(ReactiveAuthenticationManager authenticationManager, - AccessTokenManager accessTokenManager) { - return new DefaultClientCredentialGranter(authenticationManager, accessTokenManager); + AccessTokenManager accessTokenManager, + ApplicationEventPublisher eventPublisher) { + return new DefaultClientCredentialGranter(authenticationManager, accessTokenManager,eventPublisher); } @Bean @ConditionalOnMissingBean public AuthorizationCodeGranter authorizationCodeGranter(AccessTokenManager tokenManager, + ApplicationEventPublisher eventPublisher, ReactiveRedisConnectionFactory redisConnectionFactory) { - return new DefaultAuthorizationCodeGranter(tokenManager, redisConnectionFactory); + return new DefaultAuthorizationCodeGranter(tokenManager,eventPublisher, redisConnectionFactory); } @Bean diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java index 472cedfa0..38e0341f6 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranter.java @@ -4,13 +4,16 @@ import lombok.AllArgsConstructor; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.id.IDGenerator; import org.hswebframework.web.oauth2.ErrorType; +import org.hswebframework.web.oauth2.GrantType; import org.hswebframework.web.oauth2.OAuth2Constants; import org.hswebframework.web.oauth2.OAuth2Exception; import org.hswebframework.web.oauth2.server.AccessToken; import org.hswebframework.web.oauth2.server.AccessTokenManager; import org.hswebframework.web.oauth2.server.OAuth2Client; import org.hswebframework.web.oauth2.server.ScopePredicate; +import org.hswebframework.web.oauth2.server.event.OAuth2GrantedEvent; import org.hswebframework.web.oauth2.server.utils.OAuth2ScopeUtils; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; import org.springframework.data.redis.core.ReactiveRedisOperations; import org.springframework.data.redis.core.ReactiveRedisTemplate; @@ -25,11 +28,15 @@ public class DefaultAuthorizationCodeGranter implements AuthorizationCodeGranter private final AccessTokenManager accessTokenManager; + private final ApplicationEventPublisher eventPublisher; + private final ReactiveRedisOperations redis; @SuppressWarnings("all") - public DefaultAuthorizationCodeGranter(AccessTokenManager accessTokenManager, ReactiveRedisConnectionFactory connectionFactory) { - this(accessTokenManager, new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext + public DefaultAuthorizationCodeGranter(AccessTokenManager accessTokenManager, + ApplicationEventPublisher eventPublisher, + ReactiveRedisConnectionFactory connectionFactory) { + this(accessTokenManager, eventPublisher, new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext .newSerializationContext() .key((RedisSerializer) RedisSerializer.string()) .value(RedisSerializer.java()) @@ -75,16 +82,27 @@ public class DefaultAuthorizationCodeGranter implements AuthorizationCodeGranter .map(this::getRedisKey) .flatMap(redis.opsForValue()::get) .switchIfEmpty(Mono.error(() -> new OAuth2Exception(ErrorType.ILLEGAL_CODE))) - .flatMap(cache -> redis - .opsForValue() - .delete(getRedisKey(cache.getCode())) - .thenReturn(cache)) + //移除code + .flatMap(cache -> redis.opsForValue().delete(getRedisKey(cache.getCode())).thenReturn(cache)) .flatMap(cache -> { if (!request.getClient().getClientId().equals(cache.getClientId())) { return Mono.error(new OAuth2Exception(ErrorType.ILLEGAL_CLIENT_ID)); } - return accessTokenManager.createAccessToken(cache.getClientId(), cache.getAuthentication(), false); - }); + return accessTokenManager + .createAccessToken(cache.getClientId(), cache.getAuthentication(), false) + .flatMap(token -> new OAuth2GrantedEvent(request.getClient(), + token, + cache.getAuthentication(), + cache.getScope(), + GrantType.authorization_code, + request.getParameters()) + .publish(eventPublisher) + .onErrorResume(err -> accessTokenManager + .removeToken(cache.getClientId(), token.getAccessToken()) + .then(Mono.error(err))) + .thenReturn(token)); + }) + ; } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java index 74155bc44..08a78cf29 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/credential/DefaultClientCredentialGranter.java @@ -2,9 +2,12 @@ package org.hswebframework.web.oauth2.server.credential; import lombok.AllArgsConstructor; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; +import org.hswebframework.web.oauth2.GrantType; import org.hswebframework.web.oauth2.server.AccessToken; import org.hswebframework.web.oauth2.server.AccessTokenManager; import org.hswebframework.web.oauth2.server.OAuth2Client; +import org.hswebframework.web.oauth2.server.event.OAuth2GrantedEvent; +import org.springframework.context.ApplicationEventPublisher; import reactor.core.publisher.Mono; @AllArgsConstructor @@ -14,6 +17,8 @@ public class DefaultClientCredentialGranter implements ClientCredentialGranter { private final AccessTokenManager accessTokenManager; + private final ApplicationEventPublisher eventPublisher; + @Override public Mono requestToken(ClientCredentialRequest request) { @@ -21,6 +26,19 @@ public class DefaultClientCredentialGranter implements ClientCredentialGranter { return authenticationManager .getByUserId(client.getUserId()) - .flatMap(auth -> accessTokenManager.createAccessToken(client.getClientId(), auth, true)); + .flatMap(auth -> accessTokenManager + .createAccessToken(client.getClientId(), auth, true) + .flatMap(token -> new OAuth2GrantedEvent(client, + token, + auth, + "*", + GrantType.client_credentials, + request.getParameters()) + .publish(eventPublisher) + .onErrorResume(err -> accessTokenManager + .removeToken(client.getClientId(), token.getAccessToken()) + .then(Mono.error(err))) + .thenReturn(token)) + ); } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java new file mode 100644 index 000000000..38b341dcb --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/event/OAuth2GrantedEvent.java @@ -0,0 +1,32 @@ +package org.hswebframework.web.oauth2.server.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.event.DefaultAsyncEvent; +import org.hswebframework.web.oauth2.server.AccessToken; +import org.hswebframework.web.oauth2.server.OAuth2Client; + +import java.util.Map; + +/** + * OAuth2授权成功事件 + * + * @author zhouhao + * @since 4.0.15 + */ +@Getter +@AllArgsConstructor +public class OAuth2GrantedEvent extends DefaultAsyncEvent { + private final OAuth2Client client; + + private final AccessToken accessToken; + + private final Authentication authentication; + + private final String scope; + + private final String grantType; + + private final Map parameters; +} diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index fe1e9b39b..1de7183fa 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -178,4 +178,14 @@ public class RedisAccessTokenManager implements AccessTokenManager { }); } + + @Override + public Mono removeToken(String clientId, String token) { + + return Flux + .merge(userTokenManager.signOutByToken(token), + tokenRedis.delete(createSingletonTokenRedisKey(clientId)), + tokenRedis.delete(createTokenRedisKey(token))) + .then(); + } } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java index b71ee6468..123ab20f9 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/web/OAuth2AuthorizeController.java @@ -19,7 +19,9 @@ import org.hswebframework.web.oauth2.server.OAuth2GrantService; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeRequest; import org.hswebframework.web.oauth2.server.code.AuthorizationCodeTokenRequest; import org.hswebframework.web.oauth2.server.credential.ClientCredentialRequest; +import org.hswebframework.web.oauth2.server.event.OAuth2GrantedEvent; import org.hswebframework.web.oauth2.server.refresh.RefreshTokenRequest; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java b/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java index 4f9fdaacc..6e0545441 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/test/java/org/hswebframework/web/oauth2/server/code/DefaultAuthorizationCodeGranterTest.java @@ -7,6 +7,7 @@ import org.hswebframework.web.oauth2.server.OAuth2Client; import org.hswebframework.web.oauth2.server.RedisHelper; import org.hswebframework.web.oauth2.server.impl.RedisAccessTokenManager; import org.junit.Test; +import org.springframework.context.support.StaticApplicationContext; import reactor.test.StepVerifier; import java.util.Collections; @@ -20,7 +21,7 @@ public class DefaultAuthorizationCodeGranterTest { public void testRequestToken() { DefaultAuthorizationCodeGranter codeGranter = new DefaultAuthorizationCodeGranter( - new RedisAccessTokenManager(RedisHelper.factory), RedisHelper.factory + new RedisAccessTokenManager(RedisHelper.factory), new StaticApplicationContext(), RedisHelper.factory ); OAuth2Client client = new OAuth2Client(); From f2c45b037467ecf7a9e434c3e992169fbf9e5d7f Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 13:54:01 +0800 Subject: [PATCH 11/46] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/simple/SimpleAuthentication.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index e318c6c19..96b36a096 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -105,4 +105,8 @@ public class SimpleAuthentication implements Authentication { this.user = user; dimensions.add(user); } + + public void setDimensions(List dimensions) { + this.dimensions.addAll(dimensions); + } } From 6aede9dafb99eb623b4f4a4be674611584e5ee09 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 14:04:31 +0800 Subject: [PATCH 12/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/SimpleAuthentication.java | 4 ++++ ...ltReactiveAuthenticationInitializeService.java | 15 ++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java index 96b36a096..f4aac6b40 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleAuthentication.java @@ -109,4 +109,8 @@ public class SimpleAuthentication implements Authentication { public void setDimensions(List dimensions) { this.dimensions.addAll(dimensions); } + + public void addDimension(Dimension dimension) { + this.dimensions.add(dimension); + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java index 2cce5809b..e96e69d7a 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationInitializeService.java @@ -103,20 +103,17 @@ public class DefaultReactiveAuthenticationInitializeService return Flux.fromIterable(dimensionProviders) .flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId())) .cast(Dimension.class) + .doOnNext(authentication::addDimension) .collectList() - .doOnNext(authentication::setDimensions) - .flatMap(allDimension -> - Mono.zip( - getAllPermission() - , getSettings(allDimension) - .collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)) - , (_p, _s) -> handlePermission(authentication, allDimension, _p, _s) - )); + .then(Mono.defer(() -> Mono + .zip(getAllPermission(), + getSettings(authentication.getDimensions()).collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)), + (_p, _s) -> handlePermission(authentication, _p, _s) + ))); } protected SimpleAuthentication handlePermission(SimpleAuthentication authentication, - List dimensionList, Map permissions, Map> settings) { Map permissionMap = new HashMap<>(); From 48068826e1cb6d5a27e57e0865e3f652e69fff10 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 17:00:06 +0800 Subject: [PATCH 13/46] =?UTF-8?q?=E4=BC=98=E5=8C=96token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/oauth2/server/AccessTokenManager.java | 18 ++++- .../server/impl/RedisAccessTokenManager.java | 69 ++++++++++++++++--- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java index 37b484e85..7762b4e4c 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java @@ -40,5 +40,21 @@ public interface AccessTokenManager { */ Mono refreshAccessToken(String clientId, String refreshToken); - Mono removeToken(String clientId,String token); + /** + * 移除token + * + * @param clientId clientId + * @param token token + * @return void + */ + Mono removeToken(String clientId, String token); + + /** + * 取消对用户的授权 + * + * @param clientId clientId + * @param userId 用户ID + * @return void + */ + Mono cancelGrant(String clientId, String userId); } diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index 1de7183fa..c42540124 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -64,12 +64,21 @@ public class RedisAccessTokenManager implements AccessTokenManager { .map(t -> ((AuthenticationUserToken) t).getAuthentication()); } - private String createTokenRedisKey(String token) { - return "oauth2-token:" + token; + private String createTokenRedisKey(String clientId, String token) { + return "oauth2-token:" + clientId + ":" + token; } - private String createRefreshTokenRedisKey(String token) { - return "oauth2-refresh-token:" + token; + private String createUserTokenRedisKey(RedisAccessToken token) { + return createUserTokenRedisKey(token.getClientId(), token.getAuthentication().getUser().getId()); + } + + private String createUserTokenRedisKey(String clientId, String userId) { + return "oauth2-user-tokens:" + clientId + ":" + userId; + } + + + private String createRefreshTokenRedisKey(String clientId, String token) { + return "oauth2-refresh-token:" + clientId + ":" + token; } private String createSingletonTokenRedisKey(String clientId) { @@ -88,14 +97,14 @@ public class RedisAccessTokenManager implements AccessTokenManager { if (token.isSingleton()) { return userTokenManager .signIn(token.getAccessToken(), - "oauth2", + createTokenType(token.getClientId()), token.getAuthentication().getUser().getId(), tokenExpireIn * 1000L) .then(); } else { return userTokenManager .signIn(token.getAccessToken(), - "oauth2", + createTokenType(token.getClientId()), token.getAuthentication().getUser().getId(), tokenExpireIn * 1000L, token.getAuthentication()) @@ -109,10 +118,15 @@ public class RedisAccessTokenManager implements AccessTokenManager { .merge(storeAuthToken(token), tokenRedis .opsForValue() - .set(createTokenRedisKey(token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), + .set(createUserTokenRedisKey(token), token, Duration.ofSeconds(tokenExpireIn)), tokenRedis .opsForValue() - .set(createRefreshTokenRedisKey(token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn))) + .set(createTokenRedisKey(token.getClientId(), + token.getAccessToken()), token, Duration.ofSeconds(tokenExpireIn)), + tokenRedis + .opsForValue() + .set(createRefreshTokenRedisKey(token.getClientId(), + token.getRefreshToken()), token, Duration.ofSeconds(refreshExpireIn))) .then(); } @@ -144,7 +158,7 @@ public class RedisAccessTokenManager implements AccessTokenManager { @Override public Mono refreshAccessToken(String clientId, String refreshToken) { - String redisKey = createRefreshTokenRedisKey(refreshToken); + String redisKey = createRefreshTokenRedisKey(clientId, refreshToken); return tokenRedis .opsForValue() @@ -185,7 +199,42 @@ public class RedisAccessTokenManager implements AccessTokenManager { return Flux .merge(userTokenManager.signOutByToken(token), tokenRedis.delete(createSingletonTokenRedisKey(clientId)), - tokenRedis.delete(createTokenRedisKey(token))) + tokenRedis.delete(createTokenRedisKey(clientId, token))) .then(); } + + @Override + public Mono cancelGrant(String clientId, String userId) { + //删除refresh_token + Mono removeRefreshToken = tokenRedis + .opsForValue() + .get(createUserTokenRedisKey(clientId, userId)) + .flatMap(t -> tokenRedis + .opsForValue() + .delete(createRefreshTokenRedisKey(t.getClientId(), t.getRefreshToken()))) + .then(); + + //删除access_token + Mono removeAccessToken = userTokenManager + .getByUserId(userId) + .flatMap(token -> { + //其他类型的token 忽略 + if (!(createTokenType(clientId)).equals(token.getType())) { + return Mono.empty(); + } + //移除token + return tokenRedis + .delete(createTokenRedisKey(clientId, token.getToken())) + .then(userTokenManager.signOutByToken(token.getToken())); + }) + .then(); + + return Flux + .merge(removeRefreshToken, removeAccessToken) + .then(); + } + + private String createTokenType(String clientId) { + return "oauth2-" + clientId; + } } From 7160e859bc488baeb38564e5e7005c1bfa18af57 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 Aug 2022 17:13:22 +0800 Subject: [PATCH 14/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E6=8E=88=E6=9D=83=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/impl/RedisAccessTokenManager.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java index c42540124..412cb00b8 100644 --- a/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/impl/RedisAccessTokenManager.java @@ -20,6 +20,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; public class RedisAccessTokenManager implements AccessTokenManager { @@ -205,7 +207,7 @@ public class RedisAccessTokenManager implements AccessTokenManager { @Override public Mono cancelGrant(String clientId, String userId) { - //删除refresh_token + //删除最新的refresh_token Mono removeRefreshToken = tokenRedis .opsForValue() .get(createUserTokenRedisKey(clientId, userId)) @@ -222,9 +224,18 @@ public class RedisAccessTokenManager implements AccessTokenManager { if (!(createTokenType(clientId)).equals(token.getType())) { return Mono.empty(); } - //移除token return tokenRedis - .delete(createTokenRedisKey(clientId, token.getToken())) + .opsForValue() + .get(createTokenRedisKey(clientId, token.getToken())) + .flatMap(t -> { + //移除token + return tokenRedis + .delete(createTokenRedisKey(t.getClientId(), t.getAccessToken())) + //移除token对应的refresh_token + .then(tokenRedis + .opsForValue() + .delete(createRefreshTokenRedisKey(t.getClientId(), t.getRefreshToken()))); + }) .then(userTokenManager.signOutByToken(token.getToken())); }) .then(); From 9a48d78abe5335a8d79f38f90d906afc1fea3b3e Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 9 Sep 2022 14:18:45 +0800 Subject: [PATCH 15/46] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../token/redis/RedisUserTokenManager.java | 10 +++++--- .../web/bean/FastBeanCopier.java | 25 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index a33b5fa3f..f8b80b9e6 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -53,9 +53,13 @@ public class RedisUserTokenManager implements UserTokenManager { .buffer(Flux.interval(Duration.ofSeconds(10)), HashSet::new) .flatMap(list -> Flux .fromIterable(list) - .flatMap(token -> operations - .expire(getTokenRedisKey(token.getToken()), Duration.ofMillis(token.getMaxInactiveInterval())) - .then()) + .flatMap(token -> { + String key = getTokenRedisKey(token.getToken()); + return Mono + .zip(userTokenStore.put(key, "lastRequestTime", token.getLastRequestTime()), + operations.expire(key, Duration.ofMillis(token.getMaxInactiveInterval()))) + .then(); + }) .onErrorResume(err -> Mono.empty())) .subscribe(); diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index de0eea385..b8ad202e9 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -21,6 +21,7 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -513,6 +514,8 @@ public final class FastBeanCopier { if (targetClass == List.class) { return new ArrayList<>(); + } else if (targetClass == ConcurrentHashMap.KeySetView.class) { + return ConcurrentHashMap.newKeySet(); } else if (targetClass == Set.class) { return new HashSet<>(); } else if (targetClass == Queue.class) { @@ -568,7 +571,7 @@ public final class FastBeanCopier { return (T) new Date(((Date) source).getTime()); } } - if (Collection.class.isAssignableFrom(targetClass)) { + if (target.isCollectionType()) { Collection collection = newCollection(targetClass); Collection sourceCollection; if (source instanceof Collection) { @@ -619,7 +622,7 @@ public final class FastBeanCopier { Enum t = ((Enum) e); if ((t.name().equalsIgnoreCase(strSource) || Objects.equals(String.valueOf(t.ordinal()), strSource))) { - return (T)e; + return (T) e; } } @@ -642,7 +645,7 @@ public final class FastBeanCopier { //快速复制map if (targetClass == Map.class) { if (source instanceof Map) { - return (T) new HashMap(((Map) source)); + return (T) copyMap(((Map) source)); } ClassDescription sourType = ClassDescriptions.getDescription(source.getClass()); return (T) copy(source, Maps.newHashMapWithExpectedSize(sourType.getFieldSize())); @@ -656,6 +659,22 @@ public final class FastBeanCopier { // return null; } + private Map copyMap(Map map) { + if (map instanceof TreeMap) { + return new TreeMap<>(map); + } + + if (map instanceof LinkedHashMap) { + return new LinkedHashMap<>(map); + } + + if (map instanceof ConcurrentHashMap) { + return new ConcurrentHashMap<>(map); + } + + return new HashMap<>(map); + } + private Object converterByApache(Class targetClass, Object source) { org.apache.commons.beanutils.Converter converter = convertUtils.lookup(targetClass); if (null != converter) { From 24d8550bf6126d5e2bf307c0ead4de986be70f3c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 9 Sep 2022 14:19:30 +0800 Subject: [PATCH 16/46] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/authorization/token/redis/RedisUserTokenManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java index f8b80b9e6..3ff4c2b26 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/redis/RedisUserTokenManager.java @@ -56,8 +56,8 @@ public class RedisUserTokenManager implements UserTokenManager { .flatMap(token -> { String key = getTokenRedisKey(token.getToken()); return Mono - .zip(userTokenStore.put(key, "lastRequestTime", token.getLastRequestTime()), - operations.expire(key, Duration.ofMillis(token.getMaxInactiveInterval()))) + .zip(this.userTokenStore.put(key, "lastRequestTime", token.getLastRequestTime()), + this.operations.expire(key, Duration.ofMillis(token.getMaxInactiveInterval()))) .then(); }) .onErrorResume(err -> Mono.empty())) From c654222054c3a0ffed7b9693ba10755f2841826a Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 21 Sep 2022 11:06:05 +0800 Subject: [PATCH 17/46] =?UTF-8?q?=E4=BF=AE=E5=A4=8DUpdateEvent=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E8=8E=B7=E5=8F=96=E4=BF=AE=E6=94=B9=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventListener.java | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 94e82b682..aa4ae38b2 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -133,39 +133,37 @@ public class EntityEventListener implements EventListener { protected List createAfterData(List olds, EventContext context) { List newValues = new ArrayList<>(olds.size()); + EntityColumnMapping mapping = context .get(MappingContextKeys.columnMapping) .orElseThrow(UnsupportedOperationException::new); - TableOrViewMetadata table = context.get(ContextKeys.table).orElseThrow(UnsupportedOperationException::new); - RDBColumnMetadata idColumn = table - .getColumns() - .stream() - .filter(RDBColumnMetadata::isPrimaryKey) - .findFirst() - .orElse(null); - if (idColumn == null) { - return Collections.emptyList(); - } + + Map columns = context + .get(MappingContextKeys.updateColumnInstance) + .orElse(Collections.emptyMap()); + for (Object old : olds) { - Object newValue = context - .get(MappingContextKeys.updateColumnInstance) - .map(map -> { - Object data = FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.newInstance())); - for (Map.Entry entry : map.entrySet()) { - //set null - if (entry.getValue() == null - || entry.getValue() instanceof NullValue) { - GlobalConfig - .getPropertyOperator() - .setProperty(data, entry.getKey(), null); - } - } - return data; - }) - .orElseThrow(() -> { - return new IllegalArgumentException("can not get update instance"); - }); - newValues.add(newValue); + Object data = FastBeanCopier.copy(old, mapping.newInstance()); + for (Map.Entry entry : columns.entrySet()) { + + RDBColumnMetadata column = mapping.getColumnByName(entry.getKey()).orElse(null); + if (column == null) { + continue; + } + + Object value = entry.getValue(); + + //set null + if (value instanceof NullValue) { + value = null; + } + + GlobalConfig + .getPropertyOperator() + .setProperty(data, column.getAlias(), value); + + } + newValues.add(data); } return newValues; } From 3e6bcec8115c5d5fe495cf4eaeb0a0ffe1e44e37 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 21 Sep 2022 11:06:09 +0800 Subject: [PATCH 18/46] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/factory/MapperEntityFactory.java | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java index c61c6f805..d1a201c41 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/entity/factory/MapperEntityFactory.java @@ -27,8 +27,10 @@ import org.hswebframework.web.bean.FastBeanCopier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; /** @@ -37,9 +39,11 @@ import java.util.function.Supplier; */ @SuppressWarnings("unchecked") public class MapperEntityFactory implements EntityFactory, BeanFactory { - private Map realTypeMapper = new HashMap<>(); - private Logger logger = LoggerFactory.getLogger(this.getClass()); - private Map copierCache = new HashMap<>(); + @SuppressWarnings("all") + private final Map, Mapper> realTypeMapper = new ConcurrentHashMap<>(); + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + @SuppressWarnings("all") + private final Map copierCache = new ConcurrentHashMap<>(); private static final DefaultMapperFactory DEFAULT_MAPPER_FACTORY = clazz -> { String simpleClassName = clazz.getPackage().getName().concat(".Simple").concat(clazz.getSimpleName()); @@ -68,6 +72,16 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { this.realTypeMapper.putAll(realTypeMapper); } + public MapperEntityFactory addMapping(Class target, Supplier mapper) { + realTypeMapper.put(target, new Mapper(target, mapper)); + return this; + } + + public MapperEntityFactory addMappingIfAbsent(Class target, Supplier mapper) { + realTypeMapper.putIfAbsent(target, new Mapper(target, mapper)); + return this; + } + public MapperEntityFactory addMapping(Class target, Mapper mapper) { realTypeMapper.put(target, mapper); return this; @@ -216,8 +230,8 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { } public static class Mapper { - Class target; - Supplier instanceGetter; + final Class target; + final Supplier instanceGetter; public Mapper(Class target, Supplier instanceGetter) { this.target = target; @@ -242,16 +256,17 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { } static class DefaultInstanceGetter implements Supplier { - Class type; + final Constructor constructor; + @SneakyThrows public DefaultInstanceGetter(Class type) { - this.type = type; + this.constructor = type.getConstructor(); } @Override @SneakyThrows public T get() { - return type.newInstance(); + return constructor.newInstance(); } } } From 87b921528f794d5e7994ed8fdcf8331cbbc7c8bf Mon Sep 17 00:00:00 2001 From: zhouhao Date: Wed, 28 Sep 2022 18:47:24 +0800 Subject: [PATCH 19/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A1=A8=E5=90=8D?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/service/terms/DimensionTerm.java | 20 +++++++++---------- .../service/terms/UserDimensionTerm.java | 2 +- pom.xml | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java index 9760376d2..11b447e7d 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/DimensionTerm.java @@ -28,19 +28,19 @@ public class DimensionTerm extends AbstractTermFragmentBuilder { } public static > T inject(T query, - String column, - String dimensionType, - List userId) { + String column, + String dimensionType, + List userId) { return inject(query, column, dimensionType, false, false, userId); } public static > T inject(T query, - String column, - String dimensionType, - boolean not, - boolean any, - List userId) { - return (T)query.accept(column, createTermType(dimensionType, not, any), userId); + String column, + String dimensionType, + boolean not, + boolean any, + List userId) { + return (T) query.accept(column, createTermType(dimensionType, not, any), userId); } public static String createTermType(String dimensionType, boolean not, boolean any) { @@ -73,7 +73,7 @@ public class DimensionTerm extends AbstractTermFragmentBuilder { fragments.addSql("not "); } fragments - .addSql("exists(select 1 from s_dimension_user d where d.dimension_type_id = ? and d.dimension_id =", columnFullName) + .addSql("exists(select 1 from", getTableName("s_dimension_user", column), "d where d.dimension_type_id = ? and d.dimension_id =", columnFullName) .addParameter(options.get(0)); if (!options.contains("any")) { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java index 7078b197d..b63fc2b4f 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/terms/UserDimensionTerm.java @@ -37,7 +37,7 @@ public class UserDimensionTerm extends AbstractTermFragmentBuilder { fragments.addSql("not"); } - fragments.addSql("exists(select 1 from s_dimension_user d where d.user_id =", columnFullName); + fragments.addSql("exists(select 1 from ",getTableName("s_dimension_user",column)," d where d.user_id =", columnFullName); if (options.size() > 0) { String typeId = options.get(0); diff --git a/pom.xml b/pom.xml index 8854cd5de..c2ad6774a 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ 3.2.2 1.6.12 - 4.0.14 + 4.1.0-SNAPSHOT 3.0.2 3.0.2 2.7.0 From ffdd084920ed6e17c10e24032d887c67b16602e2 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 14 Oct 2022 20:11:28 +0800 Subject: [PATCH 20/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/EasyormConfiguration.java | 18 +++-- .../crud/events/CompositeEventListener.java | 3 + .../web/crud/events/CreatorEventListener.java | 71 +++++++++++++------ .../web/crud/events/EntityEventListener.java | 11 +++ 4 files changed, 76 insertions(+), 27 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java index 9042b6c9d..393ca3cb8 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/EasyormConfiguration.java @@ -38,6 +38,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; @@ -112,22 +114,24 @@ public class EasyormConfiguration { }; } + @Bean - public EntityEventListener entityEventListener(ApplicationEventPublisher eventPublisher, - ObjectProvider customizers) { - DefaultEntityEventListenerConfigure configure = new DefaultEntityEventListenerConfigure(); - customizers.forEach(customizer -> customizer.customize(configure)); - return new EntityEventListener(eventPublisher, configure); + public CreatorEventListener creatorEventListener() { + return new CreatorEventListener(); } + @Bean public ValidateEventListener validateEventListener() { return new ValidateEventListener(); } @Bean - public CreatorEventListener creatorEventListener() { - return new CreatorEventListener(); + public EntityEventListener entityEventListener(ApplicationEventPublisher eventPublisher, + ObjectProvider customizers) { + DefaultEntityEventListenerConfigure configure = new DefaultEntityEventListenerConfigure(); + customizers.forEach(customizer -> customizer.customize(configure)); + return new EntityEventListener(eventPublisher, configure); } @Bean diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java index 638850b9f..f07ece5db 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CompositeEventListener.java @@ -5,7 +5,9 @@ import lombok.Setter; import org.hswebframework.ezorm.rdb.events.EventContext; import org.hswebframework.ezorm.rdb.events.EventListener; import org.hswebframework.ezorm.rdb.events.EventType; +import org.springframework.core.Ordered; +import java.util.Comparator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -24,5 +26,6 @@ public class CompositeEventListener implements EventListener { public void addListener(EventListener eventListener) { eventListeners.add(eventListener); + eventListeners.sort(Comparator.comparingLong(e -> e instanceof Ordered ? ((Ordered) e).getOrder() : Ordered.LOWEST_PRECEDENCE)); } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java index 9662899d3..722f18a11 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java @@ -12,19 +12,21 @@ import org.hswebframework.web.api.crud.entity.RecordModifierEntity; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.validator.CreateGroup; import org.hswebframework.web.validator.UpdateGroup; +import org.springframework.core.Ordered; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Consumer; /** * 自动填充创建人和修改人信息 */ -public class CreatorEventListener implements EventListener { +public class CreatorEventListener implements EventListener, Ordered { @Override public String getId() { @@ -60,27 +62,45 @@ public class CreatorEventListener implements EventListener { } protected void doApplyCreator(EventType type, EventContext context, Authentication auth) { - context.get(MappingContextKeys.instance) - .ifPresent(obj -> { - if (obj instanceof Collection) { - applyCreator(auth, ((Collection) obj), type != MappingEventTypes.update_before); - } else { - applyCreator(auth, obj, type != MappingEventTypes.update_before); - } - }); + Object instance = context.get(MappingContextKeys.instance).orElse(null); + if (instance != null) { + if (instance instanceof Collection) { + applyCreator(auth, context, ((Collection) instance), type != MappingEventTypes.update_before); + } else { + applyCreator(auth, context, instance, type != MappingEventTypes.update_before); + } + } else { + context.get(MappingContextKeys.updateColumnInstance) + .ifPresent(map -> { + applyCreator(auth, context, map, type != MappingEventTypes.update_before); + }); + } + + } - public void applyCreator(Authentication auth, Object entity, boolean updateCreator) { - if (updateCreator && entity instanceof RecordCreationEntity) { - RecordCreationEntity e = (RecordCreationEntity) entity; - if (ObjectUtils.isEmpty(e.getCreatorId())) { - e.setCreatorId(auth.getUser().getId()); - e.setCreatorName(auth.getUser().getName()); - } - if (e.getCreateTime() == null) { - e.setCreateTimeNow(); + public void applyCreator(Authentication auth, + EventContext context, + Object entity, + boolean updateCreator) { + if (updateCreator) { + if (entity instanceof RecordCreationEntity) { + RecordCreationEntity e = (RecordCreationEntity) entity; + if (ObjectUtils.isEmpty(e.getCreatorId())) { + e.setCreatorId(auth.getUser().getId()); + e.setCreatorName(auth.getUser().getName()); + } + if (e.getCreateTime() == null) { + e.setCreateTimeNow(); + } + } else if (entity instanceof Map) { + Map map = ((Map) entity); + map.putIfAbsent("creatorId", auth.getUser().getId()); + map.putIfAbsent("creatorName", auth.getUser().getName()); + map.putIfAbsent("createTime", auth.getUser().getId()); } + } if (entity instanceof RecordModifierEntity) { RecordModifierEntity e = (RecordModifierEntity) entity; @@ -91,13 +111,24 @@ public class CreatorEventListener implements EventListener { if (e.getModifyTime() == null) { e.setModifyTimeNow(); } + } else if (entity instanceof Map) { + Map map = ((Map) entity); + map.putIfAbsent("modifierId", auth.getUser().getId()); + map.putIfAbsent("modifierName", auth.getUser().getName()); + map.putIfAbsent("modifyTime", auth.getUser().getId()); + } } - public void applyCreator(Authentication auth, Collection entities, boolean updateCreator) { + public void applyCreator(Authentication auth, EventContext context, Collection entities, boolean updateCreator) { for (Object entity : entities) { - applyCreator(auth, entity, updateCreator); + applyCreator(auth, context, entity, updateCreator); } } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index aa4ae38b2..b88ea7ecf 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -142,6 +142,17 @@ public class EntityEventListener implements EventListener { .get(MappingContextKeys.updateColumnInstance) .orElse(Collections.emptyMap()); + List newerInstance = context + .get(MappingContextKeys.instance) + .map(instance -> { + if (instance instanceof List) { + return ((List) instance); + } + return Collections.singletonList(instance); + }) + .orElse(null); + + for (Object old : olds) { Object data = FastBeanCopier.copy(old, mapping.newInstance()); for (Map.Entry entry : columns.entrySet()) { From bff95506b158037c5208abef6bb3c64862319598 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 14 Oct 2022 20:12:36 +0800 Subject: [PATCH 21/46] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E6=B8=85=E9=99=A4=E7=94=A8=E6=88=B7=E6=9D=83?= =?UTF-8?q?=E9=99=90=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../defaults/service/DefaultDimensionUserService.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java index af9489925..538d345a7 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionUserService.java @@ -56,9 +56,6 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService event) { event.async( this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new) - .then( - this.clearUserCache(event.getEntity()) - ) ); } @@ -67,9 +64,6 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService event) { event.async( this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionBindEvent::new) - .then( - this.clearUserCache(event.getEntity()) - ) ); } @@ -78,9 +72,6 @@ public class DefaultDimensionUserService extends GenericReactiveCrudService event) { event.async( this.publishEvent(Flux.fromIterable(event.getEntity()), DimensionUnbindEvent::new) - .then( - this.clearUserCache(event.getEntity()) - ) ); } From df145478164f82467d86173899ad3c8842232899 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 17 Oct 2022 11:32:32 +0800 Subject: [PATCH 22/46] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/CreatorEventListener.java | 17 ++++++++-------- .../web/crud/events/EntityEventListener.java | 20 ++++++++----------- .../crud/events/ValidateEventListener.java | 8 +++++++- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java index 722f18a11..54f1f14af 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/CreatorEventListener.java @@ -69,13 +69,11 @@ public class CreatorEventListener implements EventListener, Ordered { } else { applyCreator(auth, context, instance, type != MappingEventTypes.update_before); } - } else { - context.get(MappingContextKeys.updateColumnInstance) - .ifPresent(map -> { - applyCreator(auth, context, map, type != MappingEventTypes.update_before); - }); } + context + .get(MappingContextKeys.updateColumnInstance) + .ifPresent(map -> applyCreator(auth, context, map, type != MappingEventTypes.update_before)); } @@ -83,6 +81,7 @@ public class CreatorEventListener implements EventListener, Ordered { EventContext context, Object entity, boolean updateCreator) { + long now = System.currentTimeMillis(); if (updateCreator) { if (entity instanceof RecordCreationEntity) { RecordCreationEntity e = (RecordCreationEntity) entity; @@ -91,13 +90,13 @@ public class CreatorEventListener implements EventListener, Ordered { e.setCreatorName(auth.getUser().getName()); } if (e.getCreateTime() == null) { - e.setCreateTimeNow(); + e.setCreateTime(now); } } else if (entity instanceof Map) { Map map = ((Map) entity); map.putIfAbsent("creatorId", auth.getUser().getId()); map.putIfAbsent("creatorName", auth.getUser().getName()); - map.putIfAbsent("createTime", auth.getUser().getId()); + map.putIfAbsent("createTime", now); } @@ -109,13 +108,13 @@ public class CreatorEventListener implements EventListener, Ordered { e.setModifierName(auth.getUser().getName()); } if (e.getModifyTime() == null) { - e.setModifyTimeNow(); + e.setModifyTime(now); } } else if (entity instanceof Map) { Map map = ((Map) entity); map.putIfAbsent("modifierId", auth.getUser().getId()); map.putIfAbsent("modifierName", auth.getUser().getName()); - map.putIfAbsent("modifyTime", auth.getUser().getId()); + map.putIfAbsent("modifyTime", now); } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index b88ea7ecf..033719238 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -22,6 +22,7 @@ import org.hswebframework.web.bean.FastBeanCopier; import org.hswebframework.web.event.AsyncEvent; import org.hswebframework.web.event.GenericsPayloadApplicationEvent; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.core.Ordered; import reactor.core.publisher.Mono; import reactor.function.Function3; import reactor.util.function.Tuple2; @@ -36,7 +37,7 @@ import static org.hswebframework.web.crud.events.EntityEventHelper.*; @SuppressWarnings("all") @AllArgsConstructor -public class EntityEventListener implements EventListener { +public class EntityEventListener implements EventListener, Ordered { private final ApplicationEventPublisher eventPublisher; @@ -142,17 +143,6 @@ public class EntityEventListener implements EventListener { .get(MappingContextKeys.updateColumnInstance) .orElse(Collections.emptyMap()); - List newerInstance = context - .get(MappingContextKeys.instance) - .map(instance -> { - if (instance instanceof List) { - return ((List) instance); - } - return Collections.singletonList(instance); - }) - .orElse(null); - - for (Object old : olds) { Object data = FastBeanCopier.copy(old, mapping.newInstance()); for (Map.Entry entry : columns.entrySet()) { @@ -239,6 +229,7 @@ public class EntityEventListener implements EventListener { holder.invoke(this.doAsyncEvent(() -> { Tuple2, List> _tmp = updated.get(); if (_tmp != null) { + return sendUpdateEvent(_tmp.getT1(), _tmp.getT2(), entityType, @@ -477,4 +468,9 @@ public class EntityEventListener implements EventListener { return eventSupplier.get(); }); } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index 342dc9e92..75f70d816 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -10,11 +10,12 @@ import org.hswebframework.web.api.crud.entity.Entity; import org.hswebframework.web.i18n.LocaleUtils; import org.hswebframework.web.validator.CreateGroup; import org.hswebframework.web.validator.UpdateGroup; +import org.springframework.core.Ordered; import java.util.List; import java.util.Optional; -public class ValidateEventListener implements EventListener { +public class ValidateEventListener implements EventListener, Ordered { @Override public String getId() { @@ -73,4 +74,9 @@ public class ValidateEventListener implements EventListener { .ifPresent(entity -> entity.tryValidate(UpdateGroup.class)); } } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE - 100; + } } From 7529d9201ffa45dca41c46f0b5122b717a362f65 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 21 Oct 2022 19:13:16 +0800 Subject: [PATCH 23/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/CompositeReactiveAuthenticationManager.java | 7 ++++++- .../web/cache/supports/RedisReactiveCache.java | 5 ++--- .../web/cache/supports/UnSupportedReactiveCache.java | 5 +++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java index 7a1d5502e..79c2037c4 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java @@ -1,6 +1,7 @@ package org.hswebframework.web.authorization.simple; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.hswebframework.web.authorization.*; import reactor.core.publisher.Flux; @@ -11,6 +12,7 @@ import java.util.function.Function; import java.util.stream.Collectors; @AllArgsConstructor +@Slf4j public class CompositeReactiveAuthenticationManager implements ReactiveAuthenticationManager { private final List providers; @@ -34,7 +36,10 @@ public class CompositeReactiveAuthenticationManager implements ReactiveAuthentic .stream() .map(manager -> manager .getByUserId(userId) - .onErrorResume((err) -> Mono.empty()) + .onErrorResume((err) -> { + log.warn("get user [{}] authentication error", userId, err); + return Mono.empty(); + }) )) .flatMap(Function.identity()) .collectList() diff --git a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java index df5b53a8c..c8d6f4387 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java +++ b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/RedisReactiveCache.java @@ -64,9 +64,8 @@ public class RedisReactiveCache implements ReactiveCache { } protected Mono handleError(Throwable error) { - return Mono.fromRunnable(() -> { - log.error(error.getMessage(), error); - }); + log.error(error.getMessage(), error); + return Mono.empty(); } @Override diff --git a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java index 4200e2de7..68a2b8ed2 100644 --- a/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java +++ b/hsweb-concurrent/hsweb-concurrent-cache/src/main/java/org/hswebframework/web/cache/supports/UnSupportedReactiveCache.java @@ -15,10 +15,11 @@ import java.util.function.Supplier; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class UnSupportedReactiveCache implements ReactiveCache { - private static final UnSupportedReactiveCache INSTANCE = new UnSupportedReactiveCache(); + private static final UnSupportedReactiveCache INSTANCE = new UnSupportedReactiveCache<>(); + @SuppressWarnings("all") public static ReactiveCache getInstance() { - return INSTANCE; + return (UnSupportedReactiveCache)INSTANCE; } @Override From ce703c401efd0496c2ca5f85018cf2a60134369b Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 21 Oct 2022 19:14:49 +0800 Subject: [PATCH 24/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple/CompositeReactiveAuthenticationManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java index 79c2037c4..c7a6dc643 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java @@ -23,7 +23,10 @@ public class CompositeReactiveAuthenticationManager implements ReactiveAuthentic .stream() .map(manager -> manager .authenticate(request) - .onErrorResume((err) -> Mono.empty())) + .onErrorResume((err) -> { + log.warn("get user authenticate error", err); + return Mono.empty(); + })) .collect(Collectors.toList())) .take(1) .next(); From b3ba02961bc59715e90c370cf1483150a66a3559 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 24 Oct 2022 13:35:48 +0800 Subject: [PATCH 25/46] =?UTF-8?q?=E4=BC=98=E5=8C=96cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hswebframework/web/crud/events/EntityEventListener.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 033719238..6366b0a68 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -39,6 +39,9 @@ import static org.hswebframework.web.crud.events.EntityEventHelper.*; @AllArgsConstructor public class EntityEventListener implements EventListener, Ordered { + public static final ContextKey> readyToDeleteContextKey = ContextKey.of("readyToDelete"); + public static final ContextKey> readyToUpdateContextKey = ContextKey.of("readyToUpdate"); + private final ApplicationEventPublisher eventPublisher; private final EntityEventListenerConfigure listenerConfigure; @@ -214,6 +217,7 @@ public class EntityEventListener implements EventListener, Ordered { .collectList() .flatMap((list) -> { List after = createAfterData(list, context); + context.set(readyToUpdateContextKey,after); updated.set(Tuples.of(list, after)); return sendUpdateEvent(list, after, @@ -299,6 +303,7 @@ public class EntityEventListener implements EventListener, Ordered { .collectList() .filter(CollectionUtils::isNotEmpty) .flatMap(list -> { + context.set(readyToDeleteContextKey,list); deleted.set(list); return this .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); From fa3b0a67d0b98294f8e72af17faba01b9bf154bb Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 25 Oct 2022 18:42:42 +0800 Subject: [PATCH 26/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/events/EntityEventListener.java | 7 ++++--- .../web/crud/events/ValidateEventListener.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java index 6366b0a68..80e31bf9a 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java @@ -217,7 +217,6 @@ public class EntityEventListener implements EventListener, Ordered { .collectList() .flatMap((list) -> { List after = createAfterData(list, context); - context.set(readyToUpdateContextKey,after); updated.set(Tuples.of(list, after)); return sendUpdateEvent(list, after, @@ -301,9 +300,11 @@ public class EntityEventListener implements EventListener, Ordered { .setParam(dslUpdate.toQueryParam()) .fetch() .collectList() + .doOnNext(list->{ + context.set(readyToDeleteContextKey, list); + }) .filter(CollectionUtils::isNotEmpty) .flatMap(list -> { - context.set(readyToDeleteContextKey,list); deleted.set(list); return this .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new); @@ -476,6 +477,6 @@ public class EntityEventListener implements EventListener, Ordered { @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE; + return Ordered.LOWEST_PRECEDENCE - 100; } } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java index 75f70d816..4d52c1c14 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/ValidateEventListener.java @@ -77,6 +77,6 @@ public class ValidateEventListener implements EventListener, Ordered { @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE - 100; + return Ordered.LOWEST_PRECEDENCE - 1000; } } From 8fad92100a6e672a0adaf64f29857f3e70f5b77c Mon Sep 17 00:00:00 2001 From: zhouhao Date: Thu, 27 Oct 2022 17:20:01 +0800 Subject: [PATCH 27/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=86=85=E5=B5=8C?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../embed/EmbedAuthenticationProperties.java | 31 ++++++++++++------- .../EmbedReactiveAuthenticationManager.java | 13 +++++++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java index e4a09e3c0..1b35e4b1a 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedAuthenticationProperties.java @@ -2,6 +2,7 @@ package org.hswebframework.web.authorization.basic.embed; import lombok.Getter; import lombok.Setter; +import org.apache.commons.collections4.MapUtils; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationRequest; import org.hswebframework.web.authorization.builder.DataAccessConfigBuilderFactory; @@ -69,7 +70,10 @@ public class EmbedAuthenticationProperties implements InitializingBean { for (Map.Entry stringObjectEntry : objectMap.entrySet()) { if (stringObjectEntry.getValue() instanceof Map) { Map mapVal = ((Map) stringObjectEntry.getValue()); - boolean maybeIsList = mapVal.keySet().stream().allMatch(org.hswebframework.utils.StringUtils::isInt); + boolean maybeIsList = mapVal + .keySet() + .stream() + .allMatch(org.hswebframework.utils.StringUtils::isInt); if (maybeIsList) { stringObjectEntry.setValue(mapVal.values()); } @@ -82,20 +86,23 @@ public class EmbedAuthenticationProperties implements InitializingBean { } public Authentication authenticate(AuthenticationRequest request) { - if(request instanceof PlainTextUsernamePasswordAuthenticationRequest){ + if (MapUtils.isEmpty(users)) { + return null; + } + if (request instanceof PlainTextUsernamePasswordAuthenticationRequest) { PlainTextUsernamePasswordAuthenticationRequest pwdReq = ((PlainTextUsernamePasswordAuthenticationRequest) request); - return users.values() - .stream() - .filter(user -> - pwdReq.getUsername().equals(user.getUsername()) - && pwdReq.getPassword().equals(user.getPassword())) - .findFirst() - .map(EmbedAuthenticationInfo::getId) - .map(authentications::get) - .orElseThrow(() -> new ValidationException("用户不存在")); + for (EmbedAuthenticationInfo user : users.values()) { + if (pwdReq.getUsername().equals(user.getUsername())) { + if (pwdReq.getPassword().equals(user.getPassword())) { + return user.toAuthentication(dataAccessConfigBuilderFactory); + } + return null; + } + } + return null; } - throw new UnsupportedOperationException("不支持的授权请求:"+request); + throw new UnsupportedOperationException("不支持的授权请求:" + request); } public Optional getAuthentication(String userId) { diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java index 6aabf28d9..94fbd6739 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/embed/EmbedReactiveAuthenticationManager.java @@ -1,6 +1,8 @@ package org.hswebframework.web.authorization.basic.embed; import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationRequest; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; @@ -22,7 +24,16 @@ public class EmbedReactiveAuthenticationManager implements ReactiveAuthenticatio @Override public Mono authenticate(Mono request) { - return request.map(properties::authenticate); + if (MapUtils.isEmpty(properties.getUsers())) { + return Mono.empty(); + } + return request. + handle((req, sink) -> { + Authentication auth = properties.authenticate(req); + if (auth != null) { + sink.next(auth); + } + }); } From 1bef816dc64956f8af622927d99272b1f0a31359 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 31 Oct 2022 19:03:34 +0800 Subject: [PATCH 28/46] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/crud/web/ResponseMessageWrapperAdvice.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java index b57bcc504..d4f32299c 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/ResponseMessageWrapperAdvice.java @@ -20,6 +20,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import javax.annotation.Nonnull; +import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; @@ -82,17 +83,21 @@ public class ResponseMessageWrapperAdvice implements ResponseBodyAdvice if (body instanceof Mono) { return ((Mono) body) .map(ResponseMessage::ok) - .switchIfEmpty(Mono.just(ResponseMessage.ok())); + .switchIfEmpty(Mono.fromSupplier(ResponseMessage::ok)); } if (body instanceof Flux) { return ((Flux) body) .collectList() .map(ResponseMessage::ok) - .switchIfEmpty(Mono.just(ResponseMessage.ok())); + .switchIfEmpty(Mono.fromSupplier(ResponseMessage::ok)); } - if (body instanceof String) { + + Method method = returnType.getMethod(); + + if (method != null && returnType.getMethod().getReturnType() == String.class) { return JSON.toJSONString(ResponseMessage.ok(body)); } + return ResponseMessage.ok(body); } From 50667b9b21dc4cb748b4952537261e533b8362da Mon Sep 17 00:00:00 2001 From: zhouhao Date: Mon, 28 Nov 2022 11:56:57 +0800 Subject: [PATCH 29/46] =?UTF-8?q?=E4=BC=98=E5=8C=96map=E8=BD=AClist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/bean/FastBeanCopier.java | 15 +++++ .../web/bean/FastBeanCopierTest.java | 61 +++++++++++++++---- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java index b8ad202e9..909c99343 100644 --- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java +++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java @@ -578,6 +578,8 @@ public final class FastBeanCopier { sourceCollection = (Collection) source; } else if (source instanceof Object[]) { sourceCollection = Arrays.asList((Object[]) source); + } else if (source instanceof Map) { + sourceCollection = ((Map) source).values(); } else { if (source instanceof String) { String stringValue = ((String) source); @@ -647,6 +649,19 @@ public final class FastBeanCopier { if (source instanceof Map) { return (T) copyMap(((Map) source)); } + if (source instanceof Collection) { + Map map = new LinkedHashMap<>(); + int i = 0; + for (Object o : ((Collection) source)) { + if (genericType.length >= 2) { + map.put(convert(i++, genericType[0], EMPTY_CLASS_ARRAY), convert(o, genericType[1], EMPTY_CLASS_ARRAY)); + } else { + map.put(i++, o); + } + } + return (T) map; + + } ClassDescription sourType = ClassDescriptions.getDescription(source.getClass()); return (T) copy(source, Maps.newHashMapWithExpectedSize(sourType.getFieldSize())); } diff --git a/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java b/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java index fe7e177e4..0c73a2b45 100644 --- a/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java +++ b/hsweb-core/src/test/java/org/hswebframework/web/bean/FastBeanCopierTest.java @@ -1,16 +1,14 @@ package org.hswebframework.web.bean; import com.google.common.collect.ImmutableMap; -import jdk.nashorn.internal.objects.annotations.Getter; +import lombok.Getter; +import lombok.Setter; import org.junit.Assert; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; /** @@ -61,6 +59,43 @@ public class FastBeanCopierTest { } + @Test + public void testMapList() { + Map data = new HashMap<>(); + data.put("templates", new HashMap() { + { + put("0", Collections.singletonMap("name", "test")); + put("1", Collections.singletonMap("name", "test")); + } + }); + + Config config = FastBeanCopier.copy(data, new Config()); + + Assert.assertNotNull(config); + Assert.assertNotNull(config.templates); + System.out.println(config.templates); + Assert.assertEquals(2,config.templates.size()); + + + } + + @Getter + @Setter + public static class Config { + private List