diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Authentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Authentication.java index df3d6f6cb..135b0183e 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Authentication.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Authentication.java @@ -183,4 +183,6 @@ public interface Authentication extends Serializable { */ Map getAttributes(); + Authentication merge(Authentication source); + } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java index b6a38257b..8d8730e11 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/AuthenticationHolder.java @@ -18,6 +18,7 @@ package org.hswebframework.web.authorization; +import org.hswebframework.web.authorization.simple.SimpleAuthentication; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -54,8 +55,7 @@ public final class AuthenticationHolder { return Flux.fromStream(suppliers.stream().map(function)) .filter(Optional::isPresent) .map(Optional::get) - .reduceWith(CompositeAuthentication::new, CompositeAuthentication::merge) - .filter(CompositeAuthentication::isNotEmpty) + .reduceWith(SimpleAuthentication::new, SimpleAuthentication::merge) .map(Authentication.class::cast) .blockOptional(); } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/CompositeAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/CompositeAuthentication.java deleted file mode 100644 index fd2351ff2..000000000 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/CompositeAuthentication.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.hswebframework.web.authorization; - -import java.io.Serializable; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class CompositeAuthentication implements Authentication { - - private Map userAuthentication = new ConcurrentHashMap<>(); - - private String currentUser; - - public boolean isEmpty() { - return userAuthentication.isEmpty(); - } - - public boolean isNotEmpty() { - return !isEmpty(); - } - - @Override - public User getUser() { - - return userAuthentication - .get(currentUser) - .getUser(); - } - - @Override - public List getDimensions() { - return userAuthentication.values() - .stream() - .map(Authentication::getDimensions) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - } - - @Override - public List getRoles() { - return userAuthentication.values() - .stream() - .map(Authentication::getRoles) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - } - - @Override - public List getPermissions() { - return userAuthentication.values() - .stream() - .map(Authentication::getPermissions) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - } - - @Override - public Optional getAttribute(String name) { - return userAuthentication.values() - .stream() - .map(a -> a.getAttribute(name)) - .filter(Optional::isPresent) - .findAny() - .flatMap(Function.identity()); - } - - @Override - public Map getAttributes() { - return userAuthentication.values() - .stream() - .map(Authentication::getAttributes) - .filter(Objects::nonNull) - .reduce(new HashMap<>(),(r,s)->{r.putAll(s);return r;}); - } - - public CompositeAuthentication merge(Authentication authentication) { - String userId = authentication.getUser().getId(); - if (currentUser == null) { - currentUser = userId; - } - userAuthentication.put(userId, authentication); - return this; - } -} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Dimension.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Dimension.java index 589c16282..f40f294a3 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Dimension.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Dimension.java @@ -1,5 +1,7 @@ package org.hswebframework.web.authorization; +import org.hswebframework.web.authorization.simple.SimpleDimension; + import java.io.Serializable; import java.util.Map; import java.util.Optional; @@ -18,4 +20,20 @@ public interface Dimension extends Serializable { .map(ops -> ops.get(key)) .map(o -> (T) o); } + + default boolean typeIs(DimensionType type) { + return this.getType() == type || this.getType().getId().equals(type.getId()); + } + + default boolean typeIs(String type) { + return this.getType().getId().equals(type); + } + + static Dimension of(String id, String name, DimensionType type) { + return of(id, name, type, null); + } + + static Dimension of(String id, String name, DimensionType type, Map options) { + return SimpleDimension.of(id, name, type, options); + } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java new file mode 100644 index 000000000..06b1de6bc --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/DimensionProvider.java @@ -0,0 +1,11 @@ +package org.hswebframework.web.authorization; + +import reactor.core.publisher.Flux; + +public interface DimensionProvider { + + Flux getDimensionByUserId(String userId); + + Flux getUserIdByDimensionId(String dimensionId); + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/MultiAuthentication.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/MultiAuthentication.java deleted file mode 100644 index 1fdb69075..000000000 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/MultiAuthentication.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2019 http://www.hswebframework.org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * - */ - -package org.hswebframework.web.authorization; - -import java.util.Set; - -/** - * 多用户权限,可同时登录多个用户,调用{@link Authentication}的方法为获取当前激活用户的权限 - * - * @since 3.0 - */ -public interface MultiAuthentication extends Authentication { - - /** - * @return 所有权限信息 - */ - Set getAuthentications(); - - /** - * 激活指定的用户 - * - * @param userId 用户ID - * @return 被激活的用户, 如果用户未登录, 则返回null - */ - Authentication activate(String userId); - - /** - * 添加一个授权 - * - * @param authentication 授权信息 - */ - void addAuthentication(Authentication authentication); -} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Permission.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Permission.java index ef32fe5e2..2a41ead02 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Permission.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/Permission.java @@ -17,7 +17,6 @@ package org.hswebframework.web.authorization; -import lombok.NonNull; import org.hswebframework.web.authorization.access.DataAccessConfig; import org.hswebframework.web.authorization.access.FieldFilterDataAccessConfig; import org.hswebframework.web.authorization.access.ScopeDataAccessConfig; @@ -146,7 +145,6 @@ public interface Permission extends Serializable { return findDataAccess(conf -> FieldFilterDataAccessConfig.class.isInstance(conf) && conf.getAction().equals(action)); } - /** * 获取不能执行操作的字段 * @@ -199,7 +197,7 @@ public interface Permission extends Serializable { && scopeType.equals(((ScopeDataAccessConfig) config).getScopeType()); } - + Permission copy(); /** * 数据权限查找判断逻辑接口 * diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java index ce5f966d6..e1f929712 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationHolder.java @@ -18,6 +18,7 @@ package org.hswebframework.web.authorization; +import org.hswebframework.web.authorization.simple.SimpleAuthentication; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -53,9 +54,8 @@ public final class ReactiveAuthenticationHolder { return Flux.concat(suppliers.stream() .map(function) .collect(Collectors.toList())) - .reduceWith(CompositeAuthentication::new, CompositeAuthentication::merge) - .filter(CompositeAuthentication::isNotEmpty) - .map(Authentication.class::cast); + .reduceWith(SimpleAuthentication::new, Authentication::merge) + .filter(a -> a.getUser() != null); } /** diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationManagerProvider.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationManagerProvider.java new file mode 100644 index 000000000..79b59ba21 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/ReactiveAuthenticationManagerProvider.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.authorization; + +import reactor.core.publisher.Mono; + +public interface ReactiveAuthenticationManagerProvider { + /** + * 进行授权操作 + * + * @param request 授权请求 + * @return 授权成功则返回用户权限信息 + */ + Mono authenticate(Mono request); + + /** + * 根据用户ID获取权限信息 + * + * @param userId 用户ID + * @return 权限信息 + */ + Mono getByUserId(String userId); +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/RequiresRoles.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/RequiresRoles.java new file mode 100644 index 000000000..8d16368e1 --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/RequiresRoles.java @@ -0,0 +1,21 @@ +package org.hswebframework.web.authorization.annotation; + + +import org.springframework.core.annotation.AliasFor; + +import java.lang.annotation.*; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Dimension(type = "role", description = "控制角色") +public @interface RequiresRoles { + + @AliasFor(annotation = Dimension.class, attribute = "id") + String[] value() default {}; + + @AliasFor(annotation = Dimension.class, attribute = "logical") + Logical logical() default Logical.DEFAULT; + +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java index ccb3d90a9..543704dbc 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/annotation/Resource.java @@ -22,5 +22,7 @@ public @interface Resource { String[] description() default {}; + String[] group() default {}; + boolean merge() default true; } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourceDefinition.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourceDefinition.java index 55c5c22db..44a6a2dcc 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourceDefinition.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourceDefinition.java @@ -20,6 +20,8 @@ public class ResourceDefinition { private List actions=new ArrayList<>(); + private List group; + @Setter(value = AccessLevel.PRIVATE) private volatile Set actionIds; diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourcesDefinition.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourcesDefinition.java index c144f6e5c..f130c8191 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourcesDefinition.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/define/ResourcesDefinition.java @@ -20,7 +20,6 @@ public class ResourcesDefinition { private Phased phased = Phased.before; - public void addResource(ResourceDefinition resource, boolean merge) { ResourceDefinition definition = getResource(resource.getId()).orElse(null); if (definition != null) { @@ -49,12 +48,19 @@ public class ResourcesDefinition { } public boolean hasPermission(Permission permission) { + if (CollectionUtils.isEmpty(resources)) { + return true; + } return getResource(permission.getId()) .filter(resource -> resource.hasAction(permission.getActions())) .isPresent(); } public boolean hasPermission(Collection permissions) { + + if (CollectionUtils.isEmpty(resources)) { + return true; + } if (CollectionUtils.isEmpty(permissions)) { return false; } 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 new file mode 100644 index 000000000..68f61f2dc --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/CompositeReactiveAuthenticationManager.java @@ -0,0 +1,46 @@ +package org.hswebframework.web.authorization.simple; + +import lombok.AllArgsConstructor; +import org.hswebframework.web.authorization.*; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.function.Function; + +@AllArgsConstructor +public class CompositeReactiveAuthenticationManager implements ReactiveAuthenticationManager { + + private List providers; + + @Override + public Mono authenticate(Mono request) { + return Flux + .fromStream(providers.stream() + .map(manager -> manager + .authenticate(request) + .onErrorResume((err) -> { + return Mono.empty(); + }) + )) + .flatMap(Function.identity()) + .reduceWith(SimpleAuthentication::of, Authentication::merge) + .filter(a -> a.getUser() != null); + } + + @Override + public Mono getByUserId(String userId) { + return Flux + .fromStream(providers.stream() + .map(manager -> manager + .getByUserId(userId) + .onErrorResume((err) -> { + return Mono.empty(); + }) + )) + .flatMap(Function.identity()) + .reduceWith(SimpleAuthentication::of, Authentication::merge) + .filter(a -> a.getUser() != null); + } +} diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java index e1040e336..67e2f4cfd 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/DefaultAuthorizationAutoConfiguration.java @@ -18,6 +18,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import java.util.List; @@ -33,15 +34,22 @@ public class DefaultAuthorizationAutoConfiguration { @Bean @ConditionalOnMissingBean(UserTokenManager.class) - @ConfigurationProperties(prefix = "hsweb.authorize") + @ConfigurationProperties(prefix = "hsweb.user-token") public UserTokenManager userTokenManager() { return new DefaultUserTokenManager(); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(ReactiveAuthenticationManagerProvider.class) + public ReactiveAuthenticationManager reactiveAuthenticationManager(List providers) { + return new CompositeReactiveAuthenticationManager(providers); + } + @Bean @ConditionalOnBean(ReactiveAuthenticationManager.class) public UserTokenReactiveAuthenticationSupplier userTokenReactiveAuthenticationSupplier(UserTokenManager userTokenManager, - ReactiveAuthenticationManager authenticationManager) { + ReactiveAuthenticationManager authenticationManager) { UserTokenReactiveAuthenticationSupplier supplier = new UserTokenReactiveAuthenticationSupplier(userTokenManager, authenticationManager); ReactiveAuthenticationHolder.addSupplier(supplier); return supplier; 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 483189b24..c9d0318a7 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 @@ -18,53 +18,31 @@ package org.hswebframework.web.authorization.simple; import lombok.Getter; +import lombok.Setter; import org.hswebframework.web.authorization.*; import java.io.Serializable; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +@Getter +@Setter public class SimpleAuthentication implements Authentication { private static final long serialVersionUID = -2898863220255336528L; private User user; - private List permissions; + private List permissions = new ArrayList<>(); - private List dimensions; + private List dimensions = new ArrayList<>(); - @Getter private Map attributes = new HashMap<>(); - @Override - public User getUser() { - return user; + public static Authentication of(){ + return new SimpleAuthentication(); } - - public void setUser(User user) { - this.user = user; - } - - public void setPermissions(List permissions) { - this.permissions = permissions; - } - - @Override - public List getPermissions() { - if (permissions == null) { - return permissions = new ArrayList<>(); - } - return new ArrayList<>(permissions); - } - - @Override - public List getDimensions() { - if (dimensions == null) { - return dimensions = new ArrayList<>(); - } - return dimensions; - } - @Override @SuppressWarnings("unchecked") public Optional getAttribute(String name) { @@ -75,4 +53,28 @@ public class SimpleAuthentication implements Authentication { public Map getAttributes() { return attributes; } + + public SimpleAuthentication merge(Authentication authentication) { + Map mePermissionGroup = permissions.stream() + .collect(Collectors.toMap(Permission::getId, Function.identity())); + user = authentication.getUser(); + attributes.putAll(authentication.getAttributes()); + for (Permission permission : authentication.getPermissions()) { + Permission me = mePermissionGroup.get(permission.getId()); + if (me == null) { + permissions.add(permission.copy()); + continue; + } + me.getActions().addAll(permission.getActions()); + me.getDataAccesses().addAll(permission.getDataAccesses()); + } + + + for (Dimension dimension : authentication.getDimensions()) { + if (!getDimension(dimension.getType(), dimension.getId()).isPresent()) { + dimensions.add(dimension); + } + } + return this; + } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleDimension.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleDimension.java index 2337b4888..d8df4d036 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleDimension.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimpleDimension.java @@ -1,6 +1,8 @@ package org.hswebframework.web.authorization.simple; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.hswebframework.web.authorization.Dimension; import org.hswebframework.web.authorization.DimensionType; @@ -9,6 +11,8 @@ import java.util.Map; @Getter @Setter +@AllArgsConstructor(staticName = "of") +@NoArgsConstructor public class SimpleDimension implements Dimension { private String id; @@ -19,11 +23,5 @@ public class SimpleDimension implements Dimension { private Map options; - public boolean typeIs(DimensionType type) { - return this.type == type || this.type.getId().equals(type.getId()); - } - public boolean typeIs(String type) { - return this.type.getId().equals(type); - } } diff --git a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimplePermission.java b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimplePermission.java index 10cee5d02..cc78492a6 100644 --- a/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimplePermission.java +++ b/hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/simple/SimplePermission.java @@ -42,4 +42,14 @@ public class SimplePermission implements Permission { } return dataAccesses; } + + public Permission copy(){ + SimplePermission permission =new SimplePermission(); + + permission.setId(id); + permission.setName(name); + permission.setActions(new HashSet<>(getActions())); + permission.setDataAccesses(new HashSet<>(getDataAccesses())); + return permission; + } } 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 841c96885..169d8efd1 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 @@ -2,6 +2,7 @@ package org.hswebframework.web.authorization.basic.configuration; import org.hswebframework.web.authorization.AuthenticationManager; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; +import org.hswebframework.web.authorization.ReactiveAuthenticationManagerProvider; import org.hswebframework.web.authorization.access.DataAccessController; import org.hswebframework.web.authorization.access.DataAccessHandler; import org.hswebframework.web.authorization.basic.aop.AopMethodAuthorizeDefinitionParser; @@ -99,8 +100,8 @@ public class AuthorizingHandlerAutoConfiguration { } @Bean - @ConditionalOnMissingBean(ReactiveAuthenticationManager.class) - public ReactiveAuthenticationManager embedAuthenticationManager(EmbedAuthenticationProperties properties) { +// @ConditionalOnMissingBean(ReactiveAuthenticationManager.class) + public ReactiveAuthenticationManagerProvider embedAuthenticationManager(EmbedAuthenticationProperties properties) { return new EmbedReactiveAuthenticationManager(properties); } 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 8ad78847b..d9178a16e 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 @@ -159,6 +159,7 @@ public class DefaultBasicAuthorizeDefinition implements AopAuthorizeDefinition { for (ResourceAction action : ann.actions()) { putAnnotation(resource, action); } + resource.setGroup(new ArrayList<>(Arrays.asList(ann.group()))); resources.addResource(resource, ann.merge()); } 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 6aabefa44..3e1448df4 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 @@ -4,6 +4,7 @@ import lombok.AllArgsConstructor; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.AuthenticationRequest; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; +import org.hswebframework.web.authorization.ReactiveAuthenticationManagerProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; @@ -16,7 +17,7 @@ import reactor.core.publisher.Mono; @Order(Ordered.HIGHEST_PRECEDENCE) @AllArgsConstructor -public class EmbedReactiveAuthenticationManager implements ReactiveAuthenticationManager { +public class EmbedReactiveAuthenticationManager implements ReactiveAuthenticationManagerProvider { private EmbedAuthenticationProperties properties; diff --git a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java index c7674d1b2..d161cd8b9 100644 --- a/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java +++ b/hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizationController.java @@ -17,18 +17,19 @@ package org.hswebframework.web.authorization.basic.web; -import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.SneakyThrows; import org.hswebframework.web.authorization.Authentication; -import org.hswebframework.web.authorization.AuthenticationManager; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; import org.hswebframework.web.authorization.annotation.Authorize; -import org.hswebframework.web.authorization.events.*; +import org.hswebframework.web.authorization.events.AuthorizationBeforeEvent; +import org.hswebframework.web.authorization.events.AuthorizationDecodeEvent; +import org.hswebframework.web.authorization.events.AuthorizationFailedEvent; +import org.hswebframework.web.authorization.events.AuthorizationSuccessEvent; import org.hswebframework.web.authorization.exception.UnAuthorizedException; +import org.hswebframework.web.authorization.simple.CompositeReactiveAuthenticationManager; import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest; -import org.hswebframework.web.logging.AccessLogger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.MediaType; @@ -36,7 +37,6 @@ import org.springframework.util.Assert; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; -import javax.servlet.http.HttpServletRequest; import java.util.Map; import java.util.function.Function; @@ -45,16 +45,15 @@ import java.util.function.Function; */ @RestController @RequestMapping("${hsweb.web.mappings.authorize:authorize}") -@AccessLogger("授权") -@Api(tags = "权限-用户授权", value = "授权") public class AuthorizationController { - @Autowired - private ReactiveAuthenticationManager authenticationManager; @Autowired private ApplicationEventPublisher eventPublisher; + @Autowired + private ReactiveAuthenticationManager authenticationManager; + @GetMapping("/me") @Authorize @ApiOperation("当前登录用户权限信息") @@ -65,6 +64,7 @@ public class AuthorizationController { @PostMapping(value = "/login", consumes = MediaType.APPLICATION_JSON_VALUE) @ApiOperation("用户名密码登录,json方式") + @Authorize(ignore = true) public Mono> authorizeByJson(@ApiParam(example = "{\"username\":\"admin\",\"password\":\"admin\"}") @RequestBody Mono> parameter) { return doLogin(parameter); @@ -72,6 +72,7 @@ public class AuthorizationController { @PostMapping(value = "/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ApiOperation("用户名密码登录,参数方式") + @Authorize(ignore = true) public Mono> authorizeByUrlEncoded(@ApiParam(hidden = true) @RequestParam Map parameter) { return doLogin(Mono.just(parameter)); @@ -102,6 +103,7 @@ public class AuthorizationController { // 验证通过 return authenticationManager .authenticate(Mono.just(new PlainTextUsernamePasswordAuthenticationRequest(username, password))) + .switchIfEmpty(Mono.error(() -> new IllegalArgumentException("密码错误"))) .map(auth -> { //触发授权成功事件 AuthorizationSuccessEvent event = new AuthorizationSuccessEvent(auth, parameterGetter); diff --git a/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/web/CompositeReactiveAuthenticationManagerTest.java b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/web/CompositeReactiveAuthenticationManagerTest.java new file mode 100644 index 000000000..c3d3df3af --- /dev/null +++ b/hsweb-authorization/hsweb-authorization-basic/src/test/java/org/hswebframework/web/authorization/basic/web/CompositeReactiveAuthenticationManagerTest.java @@ -0,0 +1,56 @@ +package org.hswebframework.web.authorization.basic.web; + +import org.hswebframework.web.authorization.*; +import org.hswebframework.web.authorization.simple.CompositeReactiveAuthenticationManager; +import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest; +import org.hswebframework.web.authorization.simple.SimpleAuthentication; +import org.hswebframework.web.authorization.simple.SimpleUser; +import org.junit.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Arrays; + + +public class CompositeReactiveAuthenticationManagerTest { + + @Test + public void test() { + CompositeReactiveAuthenticationManager manager = new CompositeReactiveAuthenticationManager( + Arrays.asList( + new ReactiveAuthenticationManagerProvider() { + @Override + public Mono authenticate(Mono request) { + return Mono.error(new IllegalArgumentException("密码错误")); + } + + @Override + public Mono getByUserId(String userId) { + return Mono.empty(); + } + }, + new ReactiveAuthenticationManagerProvider() { + @Override + public Mono authenticate(Mono request) { + SimpleAuthentication authentication = new SimpleAuthentication(); + authentication.setUser(SimpleUser.builder().id("test").build()); + + return Mono.just(authentication); + } + + @Override + public Mono getByUserId(String userId) { + return Mono.empty(); + } + } + ) + ); + + manager.authenticate(Mono.just(new PlainTextUsernamePasswordAuthenticationRequest())) + .map(Authentication::getUser) + .map(User::getId) + .as(StepVerifier::create) + .expectNext("test") + .verifyComplete(); + } +} \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java index af764048d..4641f0019 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/EntityFactory.java @@ -97,7 +97,11 @@ public interface EntityFactory { * @param 泛型 * @return 实体类型 */ - Class getInstanceType(Class entityClass); + default Class getInstanceType(Class entityClass){ + return getInstanceType(entityClass,false); + } + + Class getInstanceType(Class entityClass,boolean autoRegister); /** * 拷贝对象的属性 diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java index 245787d52..931163ba7 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/SortSupportEntity.java @@ -20,8 +20,6 @@ package org.hswebframework.web.api.crud.entity; public interface SortSupportEntity extends Comparable, Entity { - String sortIndex = "sortIndex"; - Long getSortIndex(); void setSortIndex(Long sortIndex); diff --git a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java index 878e06fe3..d369cbd80 100644 --- a/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java +++ b/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java @@ -78,6 +78,13 @@ public interface TreeSupportEntity extends Entity { } } + static , PK> List expandTree2List(T parent, IDGenerator idGenerator) { + List list = new LinkedList<>(); + expandTree2List(parent, list, idGenerator); + + return list; + } + static , PK> void expandTree2List(T parent, List target, IDGenerator idGenerator) { expandTree2List(parent, target, idGenerator, null); } @@ -95,18 +102,6 @@ public interface TreeSupportEntity extends Entity { * @param 主键类型 */ static , PK> void expandTree2List(T root, List target, IDGenerator idGenerator, BiConsumer> childConsumer) { - - if (CollectionUtils.isEmpty(root.getChildren())) { - target.add(root); - return; - } - - //尝试设置id - PK parentId = root.getId(); - if (parentId == null) { - parentId = idGenerator.generate(); - root.setId(parentId); - } //尝试设置树路径path if (root.getPath() == null) { root.setPath(RandomUtil.randomChar(4)); @@ -123,6 +118,18 @@ public interface TreeSupportEntity extends Entity { } } + if (CollectionUtils.isEmpty(root.getChildren())) { + target.add(root); + return; + } + + //尝试设置id + PK parentId = root.getId(); + if (parentId == null) { + parentId = idGenerator.generate(); + root.setId(parentId); + } + //所有节点处理队列 Queue queue = new LinkedList<>(); queue.add(root); @@ -199,12 +206,13 @@ public interface TreeSupportEntity extends Entity { Objects.requireNonNull(childConsumer, "child consumer can not be null"); Objects.requireNonNull(predicateFunction, "root predicate function can not be null"); - Supplier> streamSupplier = () -> dataList.size() < 50000 ? dataList.stream() : dataList.parallelStream(); + Supplier> streamSupplier = () -> dataList.stream(); // id,node Map cache = new HashMap<>(); // parentId,children Map> treeCache = streamSupplier.get() .peek(node -> cache.put(node.getId(), node)) + .filter(e -> e.getParentId() != null) .collect(Collectors.groupingBy(TreeSupportEntity::getParentId)); Predicate rootNodePredicate = predicateFunction.apply(new TreeHelper() { diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java index 7539beb7a..25ac04049 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java @@ -37,7 +37,6 @@ public class AutoDDLProcessor implements InitializingBean { private boolean reactive; - @Override public void afterPropertiesSet() { if(entityFactory instanceof MapperEntityFactory){ 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 7f33fea09..56f97235f 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 @@ -62,7 +62,7 @@ public class EasyOrmConfiguration { @Override public EntityColumnMapping getMapping(Class entity) { - return resolver.resolve(entityFactory.getInstanceType(entity)) + return resolver.resolve(entityFactory.getInstanceType(entity,true)) .getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(entity)) .map(EntityColumnMapping.class::cast) .orElse(null); 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 91fe35eeb..b8e2374b0 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 @@ -13,7 +13,7 @@ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. - * + * */ package org.hswebframework.web.crud.entity.factory; @@ -37,9 +37,9 @@ 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<>(); + private Map realTypeMapper = new HashMap<>(); + private Logger logger = LoggerFactory.getLogger(this.getClass()); + private Map copierCache = new HashMap<>(); private static final DefaultMapperFactory DEFAULT_MAPPER_FACTORY = clazz -> { String simpleClassName = clazz.getPackage().getName().concat(".Simple").concat(clazz.getSimpleName()); @@ -64,7 +64,7 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { public MapperEntityFactory() { } - public MapperEntityFactory(Map, Mapper> realTypeMapper) { + public MapperEntityFactory(Map, Mapper> realTypeMapper) { this.realTypeMapper.putAll(realTypeMapper); } @@ -175,19 +175,28 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { @Override @SuppressWarnings("unchecked") - public Class getInstanceType(Class beanClass) { + public Class getInstanceType(Class beanClass, boolean autoRegister) { + if (beanClass == null + || beanClass.isPrimitive() + || beanClass.isArray() + || beanClass.isEnum()) { + return null; + } Mapper mapper = realTypeMapper.get(beanClass); if (null != mapper) { return mapper.getTarget(); } - mapper = initCache(beanClass); - if (mapper != null) { - return mapper.getTarget(); - } + if (autoRegister) { + mapper = initCache(beanClass); + if (mapper != null) { + return mapper.getTarget(); + } - return Modifier.isAbstract(beanClass.getModifiers()) - || Modifier.isInterface(beanClass.getModifiers()) - ? null : beanClass; + return Modifier.isAbstract(beanClass.getModifiers()) + || Modifier.isInterface(beanClass.getModifiers()) + ? null : beanClass; + } + return null; } public void setDefaultMapperFactory(DefaultMapperFactory defaultMapperFactory) { @@ -200,7 +209,7 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory { } public static class Mapper { - Class target; + Class target; Supplier instanceGetter; public Mapper(Class target, Supplier instanceGetter) { diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java index 67691d9e4..b8dfee3a2 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/generator/DefaultIdGenerator.java @@ -7,13 +7,14 @@ import lombok.extern.slf4j.Slf4j; import org.hswebframework.ezorm.core.DefaultValue; import org.hswebframework.ezorm.core.DefaultValueGenerator; import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata; +import org.hswebframework.web.id.IDGenerator; import reactor.core.publisher.Mono; import java.util.HashMap; import java.util.Map; @Slf4j -public class DefaultIdGenerator implements DefaultValueGenerator { +public class DefaultIdGenerator implements DefaultValueGenerator { @Getter @Setter @@ -45,4 +46,5 @@ public class DefaultIdGenerator implements DefaultValueGenerator { public String getName() { return "MD5"; } + + } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java index 1abb650be..f810ae338 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveCrudService.java @@ -42,26 +42,31 @@ public interface ReactiveCrudService { return publisher.flatMap(e -> findById(Mono.just(e))); } - @Transactional(rollbackFor = Throwable.class) + @Transactional default Mono save(Publisher entityPublisher) { return getRepository() .save(entityPublisher); } - @Transactional(rollbackFor = Throwable.class) + @Transactional + default Mono updateById(K id, Mono entityPublisher) { + return getRepository() + .updateById(id, entityPublisher); + } + + @Transactional default Mono insertBatch(Publisher> entityPublisher) { return getRepository() .insertBatch(entityPublisher); } - @Transactional(rollbackFor = Throwable.class) + @Transactional default Mono insert(Publisher entityPublisher) { return getRepository() .insert(entityPublisher); } - - @Transactional(rollbackFor = Throwable.class) + @Transactional default Mono deleteById(Publisher idPublisher) { return getRepository() .deleteById(idPublisher); diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java new file mode 100644 index 000000000..fed42ace3 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java @@ -0,0 +1,76 @@ +package org.hswebframework.web.crud.service; + +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.api.crud.entity.TreeSortSupportEntity; +import org.hswebframework.web.api.crud.entity.TreeSupportEntity; +import org.hswebframework.web.id.IDGenerator; +import org.reactivestreams.Publisher; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.*; +import java.util.stream.Collectors; + +public interface ReactiveTreeSortEntityService, K> + extends ReactiveCrudService { + + default Mono> queryResultToTree(Mono paramEntity) { + return query(paramEntity) + .collectList() + .map(list -> TreeSupportEntity.list2tree(list, this::setChildren, this::isRootNode)); + } + + @Override + default Mono insert(Publisher entityPublisher) { + return insertBatch(Flux.from(entityPublisher).collectList()); + } + + @Override + default Mono insertBatch(Publisher> entityPublisher) { + return this.getRepository() + .insertBatch(Flux.from(entityPublisher) + .flatMap(Flux::fromIterable) + .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator()))) + .collectList()); + } + + @Override + default Mono save(Publisher entityPublisher) { + return this.getRepository() + .save(Flux.from(entityPublisher) + //把树结构平铺 + .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator())))); + } + + @Override + default Mono updateById(K id, Mono entityPublisher) { + return save(entityPublisher + .map(e -> { + e.setId(id); + return e; + })).map(SaveResult::getTotal); + } + + @Override + default Mono deleteById(Publisher idPublisher) { + return findById(Flux.from(idPublisher)) + .flatMap(e -> createDelete() + .where() + .like$(e::getPath) + .execute()) + .collect(Collectors.summingInt(Integer::intValue)); + } + + IDGenerator getIDGenerator(); + + void setChildren(E entity, List children); + + List getChildren(E entity); + + default boolean isRootNode(E entity){ + return StringUtils.isEmpty(entity.getParentId()) || "-1".equals(String.valueOf(entity.getParentId())); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java index 94e31efd3..8e423876d 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/CommonErrorControllerAdvice.java @@ -79,7 +79,7 @@ public class CommonErrorControllerAdvice { .stream() .filter(FieldError.class::isInstance) .map(FieldError.class::cast) - .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage())) + .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(),null)) .collect(Collectors.toList()))); } @@ -90,7 +90,7 @@ public class CommonErrorControllerAdvice { .stream() .filter(FieldError.class::isInstance) .map(FieldError.class::cast) - .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage())) + .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(),null)) .collect(Collectors.toList()))); } @@ -102,7 +102,7 @@ public class CommonErrorControllerAdvice { .stream() .filter(FieldError.class::isInstance) .map(FieldError.class::cast) - .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage())) + .map(err -> new ValidationException.Detail(err.getField(), err.getDefaultMessage(),null)) .collect(Collectors.toList()))); } @@ -122,28 +122,28 @@ public class CommonErrorControllerAdvice { @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono> handleException(RuntimeException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return Mono.just(ResponseMessage.error(e.getMessage())); } @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono> handleException(NullPointerException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return Mono.just(ResponseMessage.error(e.getMessage())); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Mono> handleException(IllegalArgumentException e) { - log.error(e.getMessage()); - return Mono.just(ResponseMessage.error("illegal_argument", e.getMessage())); + log.error(e.getMessage(), e); + return Mono.just(ResponseMessage.error(400,"illegal_argument", e.getMessage())); } @ExceptionHandler @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) public Mono> handleException(MediaTypeNotSupportedStatusException e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); return Mono.just(ResponseMessage .error(415, "unsupported_media_type", "不支持的请求类型") .result(e.getSupportedMediaTypes())); 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 bcb4b3def..5da526c95 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,5 +1,6 @@ package org.hswebframework.web.crud.web; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; @@ -13,6 +14,7 @@ import org.springframework.web.reactive.accept.RequestedContentTypeResolver; public class CommonWebFluxConfiguration { @Bean + @ConditionalOnMissingBean public CommonErrorControllerAdvice commonErrorControllerAdvice(){ return new CommonErrorControllerAdvice(); } diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveDeleteController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveDeleteController.java index 16c36d483..5a7fa0567 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveDeleteController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveDeleteController.java @@ -1,15 +1,19 @@ package org.hswebframework.web.crud.web.reactive; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.DeleteAction; import org.hswebframework.web.exception.NotFoundException; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import reactor.core.publisher.Mono; public interface ReactiveDeleteController { + @Authorize(ignore = true) ReactiveRepository getRepository(); @DeleteMapping("/{id:.+}") + @DeleteAction default Mono delete(@PathVariable K id) { return getRepository() .findById(Mono.just(id)) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java index d93fd1030..17ff31c6f 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveQueryController.java @@ -6,6 +6,7 @@ import org.hswebframework.web.api.crud.entity.PagerResult; import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.authorization.Permission; import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.QueryAction; import org.hswebframework.web.exception.NotFoundException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -17,10 +18,11 @@ import java.util.Collections; public interface ReactiveQueryController { + @Authorize(ignore = true) ReactiveRepository getRepository(); @GetMapping("/_query/no-paging") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction default Flux query(QueryParamEntity query) { return getRepository() .createQuery() @@ -29,13 +31,13 @@ public interface ReactiveQueryController { } @PostMapping("/_query/no-paging") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction default Flux query(Mono query) { return query.flatMapMany(this::query); } @GetMapping("/_count") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction default Mono count(QueryParamEntity query) { return getRepository() .createQuery() @@ -44,13 +46,13 @@ public interface ReactiveQueryController { } @GetMapping("/_query") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction default Mono> queryPager(QueryParamEntity query) { return queryPager(Mono.just(query)); } @PostMapping("/_query") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction @SuppressWarnings("all") default Mono> queryPager(Mono query) { return count(query) @@ -65,13 +67,13 @@ public interface ReactiveQueryController { } @PostMapping("/_count") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction default Mono count(Mono query) { return query.flatMap(this::count); } @GetMapping("/{id:.+}") - @Authorize(action = Permission.ACTION_GET) + @QueryAction default Mono getById(@PathVariable K id) { return getRepository() .findById(Mono.just(id)) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java index f5b4cba7f..f0aad4be2 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveSaveController.java @@ -6,6 +6,7 @@ import org.hswebframework.web.api.crud.entity.RecordModifierEntity; import org.hswebframework.web.authorization.Authentication; import org.hswebframework.web.authorization.Permission; import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.SaveAction; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; @@ -13,8 +14,10 @@ import javax.validation.Valid; public interface ReactiveSaveController { + @Authorize(ignore = true) ReactiveRepository getRepository(); + @Authorize(ignore = true) default E applyCreationEntity(Authentication authentication, E entity) { RecordCreationEntity creationEntity = ((RecordCreationEntity) entity); creationEntity.setCreateTimeNow(); @@ -23,6 +26,7 @@ public interface ReactiveSaveController { return entity; } + @Authorize(ignore = true) default E applyModifierEntity(Authentication authentication, E entity) { RecordModifierEntity creationEntity = ((RecordModifierEntity) entity); creationEntity.setModifyTimeNow(); @@ -31,6 +35,7 @@ public interface ReactiveSaveController { return entity; } + @Authorize(ignore = true) default E applyAuthentication(Authentication authentication, E entity) { if (entity instanceof RecordCreationEntity) { entity = applyCreationEntity(authentication, entity); @@ -42,7 +47,7 @@ public interface ReactiveSaveController { } @PatchMapping - @Authorize(action = Permission.ACTION_UPDATE) + @SaveAction default Mono save(@RequestBody Mono payload) { return Authentication.currentReactive() .zipWith(payload, this::applyAuthentication) @@ -51,7 +56,7 @@ public interface ReactiveSaveController { } @PostMapping - @Authorize(action = Permission.ACTION_UPDATE) + @SaveAction default Mono add(@RequestBody Mono payload) { return Authentication.currentReactive() .zipWith(payload, this::applyAuthentication) @@ -60,7 +65,7 @@ public interface ReactiveSaveController { } @PutMapping("/{id}") - @Authorize(action = Permission.ACTION_UPDATE) + @SaveAction default Mono update(@PathVariable K id, @RequestBody Mono payload) { return Authentication.currentReactive() .zipWith(payload, this::applyAuthentication) diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceCrudController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceCrudController.java new file mode 100644 index 000000000..451f1c54f --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceCrudController.java @@ -0,0 +1,9 @@ +package org.hswebframework.web.crud.web.reactive; + +public interface ReactiveServiceCrudController extends + ReactiveServiceSaveController, + ReactiveServiceQueryController, + ReactiveServiceDeleteController { + + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceDeleteController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceDeleteController.java new file mode 100644 index 000000000..e3392b2df --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceDeleteController.java @@ -0,0 +1,25 @@ +package org.hswebframework.web.crud.web.reactive; + +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.DeleteAction; +import org.hswebframework.web.crud.service.ReactiveCrudService; +import org.hswebframework.web.exception.NotFoundException; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import reactor.core.publisher.Mono; + +public interface ReactiveServiceDeleteController { + @Authorize(ignore = true) + ReactiveCrudService getService(); + + @DeleteMapping("/{id:.+}") + @DeleteAction + default Mono delete(@PathVariable K id) { + return getService() + .findById(Mono.just(id)) + .switchIfEmpty(Mono.error(NotFoundException::new)) + .flatMap(e -> getService() + .deleteById(Mono.just(id)) + .thenReturn(e)); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java new file mode 100644 index 000000000..5f53b053e --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceQueryController.java @@ -0,0 +1,83 @@ +package org.hswebframework.web.crud.web.reactive; + +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.web.api.crud.entity.PagerResult; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.QueryAction; +import org.hswebframework.web.crud.service.ReactiveCrudService; +import org.hswebframework.web.exception.NotFoundException; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Collections; + +public interface ReactiveServiceQueryController { + + @Authorize(ignore = true) + ReactiveCrudService getService(); + + @GetMapping("/_query/no-paging") + @QueryAction + default Flux query(QueryParamEntity query) { + return getService() + .createQuery() + .setParam(query) + .fetch(); + } + + @PostMapping("/_query/no-paging") + @QueryAction + default Flux query(Mono query) { + return query.flatMapMany(this::query); + } + + @GetMapping("/_count") + @QueryAction + default Mono count(QueryParamEntity query) { + return getService() + .createQuery() + .setParam(query) + .count(); + } + + @GetMapping("/_query") + @QueryAction + default Mono> queryPager(QueryParamEntity query) { + return queryPager(Mono.just(query)); + } + + @PostMapping("/_query") + @QueryAction + @SuppressWarnings("all") + default Mono> queryPager(Mono query) { + return count(query) + .zipWhen(total -> { + if (total == 0) { + return Mono.just(Collections.emptyList()); + } + return query + .map(QueryParam::clone) + .flatMap(q -> query(Mono.just(q.rePaging(total))).collectList()); + }, PagerResult::of); + } + + @PostMapping("/_count") + @QueryAction + default Mono count(Mono query) { + return query.flatMap(this::count); + } + + @GetMapping("/{id:.+}") + @QueryAction + default Mono getById(@PathVariable K id) { + return getService() + .findById(Mono.just(id)) + .switchIfEmpty(Mono.error(NotFoundException::new)); + } + + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java new file mode 100644 index 000000000..817c47a60 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/web/reactive/ReactiveServiceSaveController.java @@ -0,0 +1,72 @@ +package org.hswebframework.web.crud.web.reactive; + +import org.hswebframework.web.api.crud.entity.RecordCreationEntity; +import org.hswebframework.web.api.crud.entity.RecordModifierEntity; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.SaveAction; +import org.hswebframework.web.crud.service.ReactiveCrudService; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; + +public interface ReactiveServiceSaveController { + + @Authorize(ignore = true) + ReactiveCrudService getService(); + + @Authorize(ignore = true) + default E applyCreationEntity(Authentication authentication, E entity) { + RecordCreationEntity creationEntity = ((RecordCreationEntity) entity); + creationEntity.setCreateTimeNow(); + creationEntity.setCreatorId(authentication.getUser().getId()); + + return entity; + } + + @Authorize(ignore = true) + default E applyModifierEntity(Authentication authentication, E entity) { + RecordModifierEntity creationEntity = ((RecordModifierEntity) entity); + creationEntity.setModifyTimeNow(); + creationEntity.setModifierId(authentication.getUser().getId()); + + return entity; + } + + @Authorize(ignore = true) + default E applyAuthentication(Authentication authentication, E entity) { + if (entity instanceof RecordCreationEntity) { + entity = applyCreationEntity(authentication, entity); + } + if (entity instanceof RecordModifierEntity) { + entity = applyModifierEntity(authentication, entity); + } + return entity; + } + + @PatchMapping + @SaveAction + default Mono save(@RequestBody Mono payload) { + return Authentication.currentReactive() + .zipWith(payload, this::applyAuthentication) + .switchIfEmpty(payload) + .flatMap(entity -> getService().save(Mono.just(entity)).thenReturn(entity)); + } + + @PostMapping + @SaveAction + default Mono add(@RequestBody Mono payload) { + return Authentication.currentReactive() + .zipWith(payload, this::applyAuthentication) + .switchIfEmpty(payload) + .flatMap(entity -> getService().insert(Mono.just(entity)).thenReturn(entity)); + } + + @PutMapping("/{id}") + @SaveAction + default Mono update(@PathVariable K id, @RequestBody Mono payload) { + return Authentication.currentReactive() + .zipWith(payload, this::applyAuthentication) + .switchIfEmpty(payload) + .flatMap(entity -> getService().updateById(id,Mono.just(entity)).thenReturn(entity)); + } +} diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/TestTreeSortEntity.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/TestTreeSortEntity.java new file mode 100644 index 000000000..77bbf1106 --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/entity/TestTreeSortEntity.java @@ -0,0 +1,25 @@ +package org.hswebframework.web.crud.entity; + +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity; +import org.hswebframework.web.api.crud.entity.TreeSupportEntity; + +import javax.persistence.Column; +import javax.persistence.Table; +import java.util.List; + +@Getter +@Setter +@Table(name = "test_tree_sort") +public class TestTreeSortEntity extends GenericTreeSortSupportEntity { + + + @Column + private String name; + + + private List children; + + +} diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityServiceTest.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityServiceTest.java new file mode 100644 index 000000000..539e49e0f --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityServiceTest.java @@ -0,0 +1,62 @@ +package org.hswebframework.web.crud.service; + +import org.hswebframework.ezorm.core.param.QueryParam; +import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; +import org.hswebframework.web.crud.entity.TestTreeSortEntity; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.*; + +@SpringBootTest +@RunWith(SpringJUnit4ClassRunner.class) +public class ReactiveTreeSortEntityServiceTest { + + @Autowired + private TestTreeSortEntityService sortEntityService; + + + @Test + public void testCrud(){ + TestTreeSortEntity entity=new TestTreeSortEntity(); + entity.setId("test"); + entity.setName("test"); + + TestTreeSortEntity entity2=new TestTreeSortEntity(); + entity2.setName("test2"); + + entity.setChildren(Arrays.asList(entity2)); + + sortEntityService.insert(Mono.just(entity)) + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); + + sortEntityService.save(Mono.just(entity)) + .map(SaveResult::getTotal) + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); + + sortEntityService.queryResultToTree(Mono.just(new QueryParam())) + .map(List::size) + .as(StepVerifier::create) + .expectNext(1) + .verifyComplete(); + + + sortEntityService.deleteById(Mono.just("test")) + .as(StepVerifier::create) + .expectNext(2) + .verifyComplete(); + } + +} \ No newline at end of file diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/TestTreeSortEntityService.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/TestTreeSortEntityService.java new file mode 100644 index 000000000..f878d8d8b --- /dev/null +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/service/TestTreeSortEntityService.java @@ -0,0 +1,33 @@ +package org.hswebframework.web.crud.service; + +import org.hswebframework.web.crud.entity.TestTreeSortEntity; +import org.hswebframework.web.id.IDGenerator; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class TestTreeSortEntityService extends GenericReactiveCrudService + implements ReactiveTreeSortEntityService { + + @Override + public IDGenerator getIDGenerator() { + return IDGenerator.MD5; + } + + @Override + public void setChildren(TestTreeSortEntity entity, List children) { + entity.setChildren(children); + } + + @Override + public List getChildren(TestTreeSortEntity entity) { + return entity.getChildren(); + } + + @Override + public boolean isRootNode(TestTreeSortEntity entity) { + return entity.getParentId()==null; + } + +} diff --git a/hsweb-datasource/hsweb-datasource-web/src/main/java/org/hswebframework/web/datasource/web/DatasourceController.java b/hsweb-datasource/hsweb-datasource-web/src/main/java/org/hswebframework/web/datasource/web/DatasourceController.java index b65ff271e..3036d467a 100644 --- a/hsweb-datasource/hsweb-datasource-web/src/main/java/org/hswebframework/web/datasource/web/DatasourceController.java +++ b/hsweb-datasource/hsweb-datasource-web/src/main/java/org/hswebframework/web/datasource/web/DatasourceController.java @@ -1,9 +1,7 @@ package org.hswebframework.web.datasource.web; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.hswebframework.web.authorization.Permission; -import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.QueryAction; +import org.hswebframework.web.authorization.annotation.Resource; import org.hswebframework.web.datasource.config.DynamicDataSourceConfig; import org.hswebframework.web.datasource.config.DynamicDataSourceConfigRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -15,18 +13,14 @@ import java.util.List; @RestController @RequestMapping("/datasource") -@Api(tags = "开发人员工具-数据源", value = "数据源") -@Authorize(permission = - @Authorize.Resource(value = "datasource", description = "数据源管理") -) +@Resource(id = "datasource", name = "数据源管理") public class DatasourceController { @Autowired private DynamicDataSourceConfigRepository repository; @GetMapping - @Authorize(action = Permission.ACTION_QUERY) - @ApiOperation("获取全部数据源信息") + @QueryAction public List getAllConfig() { return repository.findAll(); } diff --git a/hsweb-starter/pom.xml b/hsweb-starter/pom.xml index c4d8d6000..82e4ff679 100644 --- a/hsweb-starter/pom.xml +++ b/hsweb-starter/pom.xml @@ -27,5 +27,9 @@ hsweb-commons-crud ${project.version} + + org.springframework + spring-webflux + \ No newline at end of file diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java new file mode 100644 index 000000000..cafa28e7f --- /dev/null +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomCodecsAutoConfiguration.java @@ -0,0 +1,37 @@ +package org.hswebframework.web.starter.jackson; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.hswebframework.web.api.crud.entity.EntityFactory; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.web.codec.CodecCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.http.codec.CodecConfigurer; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(JacksonAutoConfiguration.class) +public class CustomCodecsAutoConfiguration { + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(ObjectMapper.class) + static class JacksonDecoderConfiguration { + + @Bean + @Order(1) + @ConditionalOnBean(ObjectMapper.class) + CodecCustomizer jacksonDecoderCustomizer(EntityFactory entityFactory, ObjectMapper objectMapper) { + objectMapper.setTypeFactory(new CustomTypeFactory(entityFactory)); + return (configurer) -> { + CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs(); + defaults.jackson2JsonDecoder(new CustomJackson2JsonDecoder(objectMapper)); + }; + } + + } + + +} 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 new file mode 100644 index 000000000..7531b7533 --- /dev/null +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/CustomJackson2JsonDecoder.java @@ -0,0 +1,155 @@ +package org.hswebframework.web.starter.jackson; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; +import com.fasterxml.jackson.databind.util.TokenBuffer; +import org.reactivestreams.Publisher; +import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; +import org.springframework.core.codec.CodecException; +import org.springframework.core.codec.DecodingException; +import org.springframework.core.codec.Hints; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.log.LogFormatUtils; +import org.springframework.http.codec.HttpMessageDecoder; +import org.springframework.http.codec.json.Jackson2CodecSupport; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.MimeType; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +public class CustomJackson2JsonDecoder extends Jackson2CodecSupport implements HttpMessageDecoder { + + /** + * Constructor with a Jackson {@link ObjectMapper} to use. + */ + public CustomJackson2JsonDecoder(ObjectMapper mapper, MimeType... mimeTypes) { + super(mapper, mimeTypes); + } + + + @Override + public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) { + JavaType javaType = getObjectMapper().getTypeFactory().constructType(elementType.getType()); + // Skip String: CharSequenceDecoder + "*/*" comes after + return (!CharSequence.class.isAssignableFrom(elementType.toClass()) && + getObjectMapper().canDeserialize(javaType) && supportsMimeType(mimeType)); + } + + @Override + public Flux decode(Publisher input, ResolvableType elementType, + @Nullable MimeType mimeType, @Nullable Map hints) { + + ObjectMapper mapper = getObjectMapper(); + Flux tokens = Jackson2Tokenizer.tokenize( + Flux.from(input), mapper.getFactory(), mapper, true); + + ObjectReader reader = getObjectReader(elementType, hints); + + return tokens.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 + public Mono decodeToMono(Publisher input, ResolvableType elementType, + @Nullable MimeType mimeType, @Nullable Map hints) { + + return DataBufferUtils.join(input) + .map(dataBuffer -> decode(dataBuffer, elementType, mimeType, hints)); + } + + @Override + public Object decode(DataBuffer dataBuffer, ResolvableType targetType, + @Nullable MimeType mimeType, @Nullable Map hints) throws DecodingException { + + try { + ObjectReader objectReader = getObjectReader(targetType, hints); + Object value = objectReader.readValue(dataBuffer.asInputStream()); + logValue(value, hints); + return value; + } catch (IOException ex) { + throw processException(ex); + } finally { + DataBufferUtils.release(dataBuffer); + } + } + + private ObjectReader getObjectReader(ResolvableType elementType, @Nullable Map hints) { + Assert.notNull(elementType, "'elementType' must not be null"); + MethodParameter param = getParameter(elementType); + Class contextClass = (param != null ? param.getContainingClass() : null); + Type type = elementType.resolve() == null ? elementType.getType() : elementType.resolve(); + + JavaType javaType = getJavaType(type, contextClass); + Class jsonView = (hints != null ? (Class) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null); + return jsonView != null ? + getObjectMapper().readerWithView(jsonView).forType(javaType) : + getObjectMapper().readerFor(javaType); + } + + private void logValue(@Nullable Object value, @Nullable Map hints) { + if (!Hints.isLoggingSuppressed(hints)) { + LogFormatUtils.traceDebug(logger, traceOn -> { + String formatted = LogFormatUtils.formatValue(value, !traceOn); + return Hints.getLogPrefix(hints) + "Decoded [" + formatted + "]"; + }); + } + } + + private CodecException processException(IOException ex) { + if (ex instanceof InvalidDefinitionException) { + JavaType type = ((InvalidDefinitionException) ex).getType(); + return new CodecException("Type definition error: " + type, ex); + } + if (ex instanceof JsonProcessingException) { + String originalMessage = ((JsonProcessingException) ex).getOriginalMessage(); + return new DecodingException("JSON decoding error: " + originalMessage, ex); + } + return new DecodingException("I/O error while parsing input stream", ex); + } + + + // HttpMessageDecoder... + + @Override + public Map getDecodeHints(ResolvableType actualType, ResolvableType elementType, + ServerHttpRequest request, ServerHttpResponse response) { + + return getHints(actualType); + } + + @Override + public List getDecodableMimeTypes() { + return getMimeTypes(); + } + + // Jackson2CodecSupport ... + + @Override + protected A getAnnotation(MethodParameter parameter, Class annotType) { + return parameter.getParameterAnnotation(annotType); + } + +} diff --git a/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/Jackson2Tokenizer.java b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/Jackson2Tokenizer.java new file mode 100644 index 000000000..2f86d8e97 --- /dev/null +++ b/hsweb-starter/src/main/java/org/hswebframework/web/starter/jackson/Jackson2Tokenizer.java @@ -0,0 +1,204 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hswebframework.web.starter.jackson; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.async.ByteArrayFeeder; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext; +import com.fasterxml.jackson.databind.util.TokenBuffer; +import org.springframework.core.codec.DecodingException; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import reactor.core.Exceptions; +import reactor.core.publisher.Flux; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +/** + * {@link Function} to transform a JSON stream of arbitrary size, byte array + * chunks into a {@code Flux} where each token buffer is a + * well-formed JSON object. + * + * @author Arjen Poutsma + * @author Rossen Stoyanchev + * @author Juergen Hoeller + * @since 5.0 + */ +final class Jackson2Tokenizer { + + private final JsonParser parser; + + private final DeserializationContext deserializationContext; + + private final boolean tokenizeArrayElements; + + private TokenBuffer tokenBuffer; + + private int objectDepth; + + private int arrayDepth; + + // TODO: change to ByteBufferFeeder when supported by Jackson + // See https://github.com/FasterXML/jackson-core/issues/478 + private final ByteArrayFeeder inputFeeder; + + + private Jackson2Tokenizer( + JsonParser parser, DeserializationContext deserializationContext, boolean tokenizeArrayElements) { + + this.parser = parser; + this.deserializationContext = deserializationContext; + this.tokenizeArrayElements = tokenizeArrayElements; + this.tokenBuffer = new TokenBuffer(parser, deserializationContext); + this.inputFeeder = (ByteArrayFeeder) this.parser.getNonBlockingInputFeeder(); + } + + + private List tokenize(DataBuffer dataBuffer) { + byte[] bytes = new byte[dataBuffer.readableByteCount()]; + dataBuffer.read(bytes); + DataBufferUtils.release(dataBuffer); + + try { + this.inputFeeder.feedInput(bytes, 0, bytes.length); + return parseTokenBufferFlux(); + } + catch (JsonProcessingException ex) { + throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex); + } + catch (IOException ex) { + throw Exceptions.propagate(ex); + } + } + + private Flux endOfInput() { + return Flux.defer(() -> { + this.inputFeeder.endOfInput(); + try { + return Flux.fromIterable(parseTokenBufferFlux()); + } + catch (JsonProcessingException ex) { + throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex); + } + catch (IOException ex) { + throw Exceptions.propagate(ex); + } + }); + } + + private List parseTokenBufferFlux() throws IOException { + List result = new ArrayList<>(); + + while (true) { + JsonToken token = this.parser.nextToken(); + // SPR-16151: Smile data format uses null to separate documents + if (token == JsonToken.NOT_AVAILABLE || + (token == null && (token = this.parser.nextToken()) == null)) { + break; + } + updateDepth(token); + if (!this.tokenizeArrayElements) { + processTokenNormal(token, result); + } + else { + processTokenArray(token, result); + } + } + return result; + } + + private void updateDepth(JsonToken token) { + switch (token) { + case START_OBJECT: + this.objectDepth++; + break; + case END_OBJECT: + this.objectDepth--; + break; + case START_ARRAY: + this.arrayDepth++; + break; + case END_ARRAY: + this.arrayDepth--; + break; + } + } + + private void processTokenNormal(JsonToken token, List result) throws IOException { + this.tokenBuffer.copyCurrentEvent(this.parser); + + if ((token.isStructEnd() || token.isScalarValue()) && this.objectDepth == 0 && this.arrayDepth == 0) { + result.add(this.tokenBuffer); + this.tokenBuffer = new TokenBuffer(this.parser, this.deserializationContext); + } + + } + + private void processTokenArray(JsonToken token, List result) throws IOException { + if (!isTopLevelArrayToken(token)) { + this.tokenBuffer.copyCurrentEvent(this.parser); + } + + if (this.objectDepth == 0 && (this.arrayDepth == 0 || this.arrayDepth == 1) && + (token == JsonToken.END_OBJECT || token.isScalarValue())) { + result.add(this.tokenBuffer); + this.tokenBuffer = new TokenBuffer(this.parser, this.deserializationContext); + } + } + + private boolean isTopLevelArrayToken(JsonToken token) { + return this.objectDepth == 0 && ((token == JsonToken.START_ARRAY && this.arrayDepth == 1) || + (token == JsonToken.END_ARRAY && this.arrayDepth == 0)); + } + + + /** + * Tokenize the given {@code Flux} into {@code Flux}. + * @param dataBuffers the source data buffers + * @param jsonFactory the factory to use + * @param objectMapper the current mapper instance + * @param tokenizeArrayElements if {@code true} and the "top level" JSON object is + * an array, each element is returned individually immediately after it is received + * @return the resulting token buffers + */ + public static Flux tokenize(Flux dataBuffers, JsonFactory jsonFactory, + ObjectMapper objectMapper, boolean tokenizeArrayElements) { + + try { + JsonParser parser = jsonFactory.createNonBlockingByteArrayParser(); + DeserializationContext context = objectMapper.getDeserializationContext(); + if (context instanceof DefaultDeserializationContext) { + context = ((DefaultDeserializationContext) context).createInstance( + objectMapper.getDeserializationConfig(), parser, objectMapper.getInjectableValues()); + } + Jackson2Tokenizer tokenizer = new Jackson2Tokenizer(parser, context, tokenizeArrayElements); + return dataBuffers.concatMapIterable(tokenizer::tokenize).concatWith(tokenizer.endOfInput()); + } + catch (IOException ex) { + return Flux.error(ex); + } + } + +} diff --git a/hsweb-starter/src/main/resources/META-INF/spring.factories b/hsweb-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..01f68b173 --- /dev/null +++ b/hsweb-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.hswebframework.web.starter.jackson.CustomCodecsAutoConfiguration \ No newline at end of file diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/PermissionDimension.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/PermissionDimension.java deleted file mode 100644 index a575751d5..000000000 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/PermissionDimension.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.hswebframework.web.system.authorization.api; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.hswebframework.web.authorization.DimensionType; - -import java.util.Map; - -@Getter -@Setter -@AllArgsConstructor(staticName = "of") -@NoArgsConstructor -public class PermissionDimension { - - private String id; - - private DimensionType dimensionType; - - private Map properties; - - public static PermissionDimension of(String id, DimensionType dimensionType) { - return of(id, dimensionType, null); - } -} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/PermissionDimensionProvider.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/PermissionDimensionProvider.java deleted file mode 100644 index dcb015e1f..000000000 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/PermissionDimensionProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.hswebframework.web.system.authorization.api; - -import reactor.core.publisher.Flux; - -public interface PermissionDimensionProvider { - - Flux getDimensionByUserId(String userId); - - Flux getUserIdByDimensionId(String dimensionId); - -} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/UserPermissionDimensionProvider.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/UserDimensionProvider.java similarity index 50% rename from hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/UserPermissionDimensionProvider.java rename to hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/UserDimensionProvider.java index 5ab70b456..b110d88bf 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/UserPermissionDimensionProvider.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/UserDimensionProvider.java @@ -1,14 +1,16 @@ package org.hswebframework.web.system.authorization.api; import org.hswebframework.web.authorization.DefaultDimensionType; +import org.hswebframework.web.authorization.Dimension; +import org.hswebframework.web.authorization.DimensionProvider; import reactor.core.publisher.Flux; -public class UserPermissionDimensionProvider implements PermissionDimensionProvider { +public class UserDimensionProvider implements DimensionProvider { @Override - public Flux getDimensionByUserId(String userId) { + public Flux getDimensionByUserId(String userId) { return Flux.just(userId) - .map(id -> PermissionDimension.of(userId, DefaultDimensionType.user)); + .map(id -> Dimension.of(userId, userId, DefaultDimensionType.user)); } @Override diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java index ce341c7de..005799b2e 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/AuthorizationSettingEntity.java @@ -4,10 +4,14 @@ import lombok.Getter; import lombok.Setter; import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType; import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; +import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; import org.hswebframework.ezorm.rdb.mapping.annotation.JsonCodec; import org.hswebframework.web.api.crud.entity.Entity; +import org.hswebframework.web.validator.CreateGroup; import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; import java.sql.JDBCType; import java.util.List; import java.util.Set; @@ -25,10 +29,12 @@ public class AuthorizationSettingEntity implements Entity { @Column(length = 32, nullable = false, updatable = false) @Comment("权限ID") + @NotBlank(message = "权限ID不能为空",groups = CreateGroup.class) private String permission; - @Column(length = 32, updatable = false) + @Column(length = 32, nullable = false,updatable = false) @Comment("维度")//如:user,role + @NotBlank(message = "维度不能为空",groups = CreateGroup.class) private String dimension; @Column(name = "dimension_name", length = 64) @@ -37,6 +43,7 @@ public class AuthorizationSettingEntity implements Entity { @Column(name = "setting_target", length = 32, updatable = false) @Comment("维度目标")//具体的某个维度实例ID + @NotBlank(message = "维度目标不能为空",groups = CreateGroup.class) private String settingTarget; @Column(name = "setting_target_name", length = 64, updatable = false) @@ -45,6 +52,7 @@ public class AuthorizationSettingEntity implements Entity { @Column(name = "state", nullable = false) @Comment("状态") + @NotNull(message = "状态不能为空",groups = CreateGroup.class) private Byte state; @Column @@ -60,8 +68,10 @@ public class AuthorizationSettingEntity implements Entity { private List dataAccesses; @Column + @Comment("优先级") private Integer priority; @Column + @Comment("是否合并") private Boolean merge; } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java index 633da9f30..ad8c0482d 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-api/src/main/java/org/hswebframework/web/system/authorization/api/entity/PermissionEntity.java @@ -19,7 +19,7 @@ import java.util.Map; @Builder @NoArgsConstructor @AllArgsConstructor -public class PermissionEntity extends GenericEntity { +public class PermissionEntity extends GenericEntity { @Column @Comment("权限名称") 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 aa92907fa..025ca532c 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 @@ -3,11 +3,13 @@ package org.hswebframework.web.system.authorization.defaults.configuration; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService; import org.hswebframework.web.authorization.ReactiveAuthenticationManager; -import org.hswebframework.web.system.authorization.api.UserPermissionDimensionProvider; +import org.hswebframework.web.authorization.ReactiveAuthenticationManagerProvider; +import org.hswebframework.web.system.authorization.api.UserDimensionProvider; import org.hswebframework.web.system.authorization.api.service.reactive.ReactiveUserService; import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationInitializeService; import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationManager; import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveUserService; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -17,9 +19,7 @@ import org.springframework.context.annotation.Configuration; @Configuration public class AuthorizationServiceAutoConfiguration { - - - @Configuration + @Configuration(proxyBeanMethods = false) static class ReactiveAuthorizationServiceAutoConfiguration{ @ConditionalOnBean(ReactiveRepository.class) @Bean @@ -27,10 +27,9 @@ public class AuthorizationServiceAutoConfiguration { return new DefaultReactiveUserService(); } - @ConditionalOnMissingBean - @ConditionalOnBean(ReactiveUserService.class) @Bean - public ReactiveAuthenticationManager reactiveAuthenticationManager() { + @ConditionalOnBean(ReactiveUserService.class) + public ReactiveAuthenticationManagerProvider defaultReactiveAuthenticationManager() { return new DefaultReactiveAuthenticationManager(); } @@ -41,8 +40,8 @@ public class AuthorizationServiceAutoConfiguration { } @Bean - public UserPermissionDimensionProvider userPermissionDimensionProvider(){ - return new UserPermissionDimensionProvider(); + public UserDimensionProvider userPermissionDimensionProvider(){ + return new UserDimensionProvider(); } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java index 159d6abad..ad1ccfca2 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/configuration/AuthorizationWebAutoConfiguration.java @@ -10,7 +10,7 @@ import org.springframework.context.annotation.Configuration; public class AuthorizationWebAutoConfiguration { - @Configuration + @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) public static class WebFluxAuthorizationConfiguration { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java new file mode 100644 index 000000000..4d3a64c2e --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java @@ -0,0 +1,32 @@ +package org.hswebframework.web.system.authorization.defaults.service; + +import org.hswebframework.web.crud.service.GenericReactiveCrudService; +import org.hswebframework.web.crud.service.ReactiveTreeSortEntityService; +import org.hswebframework.web.id.IDGenerator; +import org.hswebframework.web.system.authorization.api.entity.DimensionEntity; +import org.springframework.util.StringUtils; + +import java.util.List; + +public class DefaultDimensionService + extends GenericReactiveCrudService + implements ReactiveTreeSortEntityService { + + @Override + public IDGenerator getIDGenerator() { + return IDGenerator.MD5; + } + + @Override + public void setChildren(DimensionEntity entity, List children) { + entity.setChildren(children); + } + + @Override + public List getChildren(DimensionEntity entity) { + return entity.getChildren(); + } + + + +} 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 17df6d555..b1226aff4 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 @@ -3,16 +3,17 @@ package org.hswebframework.web.system.authorization.defaults.service; import org.apache.commons.collections.CollectionUtils; import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.Dimension; import org.hswebframework.web.authorization.Permission; import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService; 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.simple.SimpleAuthentication; import org.hswebframework.web.authorization.simple.SimplePermission; import org.hswebframework.web.authorization.simple.SimpleUser; import org.hswebframework.web.authorization.simple.builder.SimpleDataAccessConfigBuilderFactory; -import org.hswebframework.web.system.authorization.api.PermissionDimension; -import org.hswebframework.web.system.authorization.api.PermissionDimensionProvider; +import org.hswebframework.web.authorization.DimensionProvider; import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity; import org.hswebframework.web.system.authorization.api.entity.PermissionEntity; import org.hswebframework.web.system.authorization.api.entity.UserEntity; @@ -41,7 +42,7 @@ public class DefaultReactiveAuthenticationInitializeService private DataAccessConfigBuilderFactory builderFactory = new SimpleDataAccessConfigBuilderFactory(); @Autowired(required = false) - private List dimensionProviders = new ArrayList<>(); + private List dimensionProviders = new ArrayList<>(); @Override public Mono initUserAuthorization(String userId) { @@ -68,13 +69,14 @@ public class DefaultReactiveAuthenticationInitializeService return Flux.fromIterable(dimensionProviders) .flatMap(provider -> provider.getDimensionByUserId(authentication.getUser().getId())) .collectList() + .doOnNext(authentication::setDimensions) .flatMap(allDimension -> Mono.zip(getAllPermission(), settingRepository .createQuery() .where(AuthorizationSettingEntity::getState, 1) .in(AuthorizationSettingEntity::getDimension, allDimension .stream() - .map(PermissionDimension::getId) + .map(Dimension::getId) .collect(Collectors.toList())) .fetch() .collect(Collectors.groupingBy(AuthorizationSettingEntity::getPermission)) @@ -83,10 +85,11 @@ public class DefaultReactiveAuthenticationInitializeService } protected SimpleAuthentication handlePermission(SimpleAuthentication authentication, - List dimensionList, + List dimensionList, Map permissions, Map> settings) { List permissionList = new ArrayList<>(); + for (PermissionEntity value : permissions.values()) { List permissionSettings = settings.get(value.getId()); if (CollectionUtils.isEmpty(permissionSettings)) { @@ -96,7 +99,7 @@ public class DefaultReactiveAuthenticationInitializeService SimplePermission permission = new SimplePermission(); permission.setId(value.getId()); permission.setName(value.getName()); - Map configs = new HashMap<>(); + Map configs = new HashMap<>(); for (AuthorizationSettingEntity permissionSetting : permissionSettings) { diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java index 15072a62a..bff69cfd6 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultReactiveAuthenticationManager.java @@ -1,9 +1,6 @@ package org.hswebframework.web.system.authorization.defaults.service; -import org.hswebframework.web.authorization.Authentication; -import org.hswebframework.web.authorization.AuthenticationRequest; -import org.hswebframework.web.authorization.ReactiveAuthenticationInitializeService; -import org.hswebframework.web.authorization.ReactiveAuthenticationManager; +import org.hswebframework.web.authorization.*; import org.hswebframework.web.authorization.exception.AccessDenyException; import org.hswebframework.web.authorization.simple.PlainTextUsernamePasswordAuthenticationRequest; import org.hswebframework.web.system.authorization.api.entity.UserEntity; @@ -13,7 +10,7 @@ import org.springframework.cache.CacheManager; import org.springframework.cache.support.SimpleValueWrapper; import reactor.core.publisher.Mono; -public class DefaultReactiveAuthenticationManager implements ReactiveAuthenticationManager { +public class DefaultReactiveAuthenticationManager implements ReactiveAuthenticationManagerProvider { @Autowired private ReactiveUserService reactiveUserService; 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 ccc7c1ae6..5deff4147 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 @@ -91,15 +91,14 @@ public class DefaultReactiveUserService extends GenericReactiveCrudService findById(String id) { return getRepository().findById(Mono.just(id)); } @Override - @Transactional(readOnly = true, transactionManager = "connectionFactoryTransactionManager") + @Transactional(readOnly = true, transactionManager = TransactionManagers.r2dbcTransactionManager) public Mono findByUsername(String username) { return Mono.justOrEmpty(username) .flatMap(_name -> repository.createQuery() @@ -108,7 +107,7 @@ public class DefaultReactiveUserService extends GenericReactiveCrudService findByUsernameAndPassword(String username, String plainPassword) { return Mono.justOrEmpty(username) .flatMap(_name -> repository @@ -120,7 +119,7 @@ public class DefaultReactiveUserService extends GenericReactiveCrudService changeState(Publisher userId, byte state) { return Flux.from(userId) .collectList() @@ -133,7 +132,7 @@ public class DefaultReactiveUserService extends GenericReactiveCrudService changePassword(String userId, String oldPassword, String newPassword) { return findById(userId) .switchIfEmpty(Mono.error(NotFoundException::new)) @@ -147,7 +146,7 @@ public class DefaultReactiveUserService extends GenericReactiveCrudService findUser(QueryParam queryParam) { return repository .createQuery() @@ -156,7 +155,7 @@ public class DefaultReactiveUserService extends GenericReactiveCrudService countUser(QueryParam queryParam) { return repository .createQuery() diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxAuthorizationSettingController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxAuthorizationSettingController.java new file mode 100644 index 000000000..c0ec7608c --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxAuthorizationSettingController.java @@ -0,0 +1,26 @@ +package org.hswebframework.web.system.authorization.defaults.webflux; + + +import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.Resource; +import org.hswebframework.web.crud.web.reactive.ReactiveCrudController; +import org.hswebframework.web.system.authorization.api.entity.AuthorizationSettingEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/autz-setting") +@Authorize +@Resource(id = "autz-setting",name = "权限分配",group = "system") +public class WebFluxAuthorizationSettingController implements ReactiveCrudController { + + @Autowired + private ReactiveRepository reactiveRepository; + + @Override + public ReactiveRepository getRepository() { + return reactiveRepository; + } +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionController.java new file mode 100644 index 000000000..a6dc320f1 --- /dev/null +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxDimensionController.java @@ -0,0 +1,37 @@ +package org.hswebframework.web.system.authorization.defaults.webflux; + +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.QueryAction; +import org.hswebframework.web.authorization.annotation.Resource; +import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController; +import org.hswebframework.web.system.authorization.api.entity.DimensionEntity; +import org.hswebframework.web.system.authorization.defaults.service.DefaultDimensionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +import java.util.List; + +@RestController +@RequestMapping("/dimension") +@Authorize +@Resource(id = "dimension",name = "权限维度管理",group = "system") +public class WebFluxDimensionController implements ReactiveServiceCrudController { + + @Autowired + private DefaultDimensionService defaultDimensionService; + + @GetMapping("/_query/tree") + @QueryAction + public Mono> findAllTree(QueryParamEntity paramEntity) { + return defaultDimensionService.queryResultToTree(Mono.just(paramEntity)); + } + + @Override + public DefaultDimensionService getService() { + return defaultDimensionService; + } +} diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java index bbafd6218..0e7dd30a4 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxPermissionController.java @@ -6,6 +6,8 @@ import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult; import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.authorization.Permission; import org.hswebframework.web.authorization.annotation.Authorize; +import org.hswebframework.web.authorization.annotation.QueryAction; +import org.hswebframework.web.authorization.annotation.Resource; import org.hswebframework.web.exception.NotFoundException; import org.hswebframework.web.system.authorization.api.entity.PermissionEntity; import org.reactivestreams.Publisher; @@ -18,14 +20,15 @@ import java.util.List; @RestController @RequestMapping("/permission") -@Authorize(permission = "permission", description = "权限管理") +@Authorize +@Resource(id = "permission",name = "权限管理",group = "system") public class WebFluxPermissionController { @Autowired private ReactiveRepository repository; @GetMapping - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction public Flux findAllPermission(QueryParamEntity paramEntity) { return repository.createQuery() .setParam(paramEntity) @@ -33,7 +36,7 @@ public class WebFluxPermissionController { } @GetMapping("/{id}") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction public Mono getPermission(@PathVariable String id) { return Mono.just(id) .as(repository::findById) @@ -41,7 +44,7 @@ public class WebFluxPermissionController { } @GetMapping("/count") - @Authorize(action = Permission.ACTION_QUERY) + @QueryAction public Mono countAllPermission(QueryParamEntity paramEntity) { return repository.createQuery() .setParam(paramEntity) @@ -50,13 +53,13 @@ public class WebFluxPermissionController { } @PatchMapping - @Authorize(action = Permission.ACTION_UPDATE) + @QueryAction public Mono savePermission(@RequestBody Publisher paramEntity) { return repository.save(paramEntity); } @PutMapping("/status/{status}") - @Authorize(action = Permission.ACTION_UPDATE) + @QueryAction public Mono changePermissionState(@PathVariable Byte status, @RequestBody List idList) { return Mono.just(idList) diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java index 91eec6997..78061730c 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/webflux/WebFluxUserController.java @@ -1,14 +1,70 @@ package org.hswebframework.web.system.authorization.defaults.webflux; +import lombok.Getter; +import lombok.Setter; +import org.hswebframework.web.authorization.Authentication; +import org.hswebframework.web.authorization.User; import org.hswebframework.web.authorization.annotation.Authorize; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.hswebframework.web.authorization.annotation.Resource; +import org.hswebframework.web.authorization.annotation.SaveAction; +import org.hswebframework.web.authorization.exception.UnAuthorizedException; +import org.hswebframework.web.crud.web.reactive.ReactiveServiceQueryController; +import org.hswebframework.web.system.authorization.api.entity.UserEntity; +import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; @RestController @RequestMapping("/user") @Authorize -public class WebFluxUserController { +@Resource(id = "user", name = "系统用户", group = "system") +public class WebFluxUserController implements ReactiveServiceQueryController { + @Autowired + private DefaultReactiveUserService reactiveUserService; + @PatchMapping + @SaveAction + public Mono saveUser(@RequestBody Mono user) { + return Authentication + .currentReactive() + .zipWith(user, ((u, e) -> { + e.setCreateTimeNow(); + e.setCreatorId(u.getUser().getId()); + return e; + })) + .switchIfEmpty(user) + .as(reactiveUserService::saveUser); + } + @PutMapping("/{id:.+}/{state}") + @SaveAction + public Mono changeState(@PathVariable String id, @PathVariable Byte state) { + return reactiveUserService.changeState(Mono.just(id), state); + } + + @PutMapping("/passwd") + @Authorize(merge = false) + public Mono changePassword(@RequestBody ChangePasswordRequest request) { + return Authentication + .currentReactive() + .switchIfEmpty(Mono.error(UnAuthorizedException::new)) + .map(Authentication::getUser) + .map(User::getId) + .flatMap(userId -> reactiveUserService.changePassword(userId, request.getOldPassword(), request.getNewPassword())); + } + + @Override + public DefaultReactiveUserService getService() { + return reactiveUserService; + } + + @Getter + @Setter + public static class ChangePasswordRequest { + private String oldPassword; + + private String newPassword; + } } diff --git a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java index 5a87074ae..e3137ef65 100644 --- a/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java +++ b/hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/test/java/org/hswebframework/web/system/authorization/defaults/service/reactive/ReactiveTestApplication.java @@ -1,17 +1,9 @@ package org.hswebframework.web.system.authorization.defaults.service.reactive; import org.hswebframework.web.crud.configuration.JdbcSqlExecutorConfiguration; -import org.hswebframework.web.system.authorization.api.UserPermissionDimensionProvider; -import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationInitializeService; -import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveAuthenticationManager; -import org.hswebframework.web.system.authorization.defaults.service.DefaultReactiveUserService; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.reactive.ReactiveTransactionAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication(exclude = { //TransactionAutoConfiguration.class,