From a5ffeae42fe7e0be0e35b8fbe833b4c9514f488d Mon Sep 17 00:00:00 2001 From: wangyu <727842003@qq.com> Date: Tue, 7 Dec 2021 22:43:03 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=AE=9E=E7=8E=B0=E5=85=A8?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/auditor/AuthorizeAuditor.java | 24 ++++ .../auditor/ReactiveAuthorizeAuditor.java | 29 ++++ .../domain/authorized/AuthorizedDomain.java | 0 .../domain/authorized/AuthorizedQo.java | 37 ++++++ .../authorized/AuthorizedUserDetails.java | 18 +++ .../flyfish/framework/domain/base/BaseQo.java | 7 +- .../com/flyfish/framework/domain/base/Qo.java | 4 +- .../config/AuthenticationAuditorImpl.java | 10 +- .../framework/config/WebSecurityConfig.java | 4 +- .../config/audit/ReactiveUserAuditor.java | 4 +- .../config/audit/UserBeanAuditor.java | 5 +- .../framework/controller/UserController.java | 12 +- .../authorized/AuthorizedController.java | 125 ++++++++++++++++++ .../ReactiveAuthorizedController.java | 100 ++++++++++++++ .../framework/domain/AdminUserDetails.java | 7 +- .../domain/authorized/AuthorizedQo.java | 64 --------- .../framework/service/DepartmentService.java | 11 +- .../service/MongoUserDetailsServiceImpl.java | 26 ++-- .../service/ReactiveUserService.java | 28 ---- .../service/UserDetailsConverter.java | 51 +++++++ .../framework/service/UserService.java | 22 ++- .../configuration/annotations/PagedQuery.java | 1 + .../resolver/PageQueryArgumentResolver.java | 8 +- .../service/impl/BaseReactiveServiceImpl.java | 22 ++- .../service/impl/BaseServiceImpl.java | 13 +- .../flyfish/framework/utils/UserUtils.java | 20 +++ 26 files changed, 500 insertions(+), 152 deletions(-) create mode 100644 flyfish-data/src/main/java/com/flyfish/framework/auditor/AuthorizeAuditor.java create mode 100644 flyfish-data/src/main/java/com/flyfish/framework/auditor/ReactiveAuthorizeAuditor.java rename {flyfish-user => flyfish-data}/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java (100%) create mode 100644 flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java create mode 100644 flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedUserDetails.java create mode 100644 flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/AuthorizedController.java create mode 100644 flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/ReactiveAuthorizedController.java delete mode 100644 flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java delete mode 100644 flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java create mode 100644 flyfish-user/src/main/java/com/flyfish/framework/service/UserDetailsConverter.java diff --git a/flyfish-data/src/main/java/com/flyfish/framework/auditor/AuthorizeAuditor.java b/flyfish-data/src/main/java/com/flyfish/framework/auditor/AuthorizeAuditor.java new file mode 100644 index 0000000..9231f1f --- /dev/null +++ b/flyfish-data/src/main/java/com/flyfish/framework/auditor/AuthorizeAuditor.java @@ -0,0 +1,24 @@ +package com.flyfish.framework.auditor; + +import com.flyfish.framework.context.UserContext; +import com.flyfish.framework.domain.authorized.AuthorizedDomain; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class AuthorizeAuditor implements BeanAuditor { + + private final UserContext userContext; + + /** + * 对实体进行审查,并补全相关字段 + * + * @param data 原数据 + * @return 结果 + */ + @Override + public void audit(AuthorizedDomain data) { + data.setAuthorizeId(userContext.currentUser().getAuthority()); + } +} diff --git a/flyfish-data/src/main/java/com/flyfish/framework/auditor/ReactiveAuthorizeAuditor.java b/flyfish-data/src/main/java/com/flyfish/framework/auditor/ReactiveAuthorizeAuditor.java new file mode 100644 index 0000000..d83072a --- /dev/null +++ b/flyfish-data/src/main/java/com/flyfish/framework/auditor/ReactiveAuthorizeAuditor.java @@ -0,0 +1,29 @@ +package com.flyfish.framework.auditor; + +import com.flyfish.framework.domain.authorized.AuthorizedDomain; +import com.flyfish.framework.domain.base.IUser; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +@Component +@RequiredArgsConstructor +public class ReactiveAuthorizeAuditor implements ReactiveBeanAuditor { + + /** + * 对实体进行审查,并补全相关字段 + * + * @param data 原数据 + * @return 结果 + */ + @Override + public Mono audit(AuthorizedDomain data) { + return ReactiveSecurityContextHolder.getContext() + .map(ctx -> (IUser) ctx.getAuthentication().getPrincipal()) + .map(user -> { + data.setAuthorizeId(user.getAuthority()); + return data; + }); + } +} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java b/flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java similarity index 100% rename from flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java rename to flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedDomain.java diff --git a/flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java b/flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java new file mode 100644 index 0000000..4123e4d --- /dev/null +++ b/flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java @@ -0,0 +1,37 @@ +package com.flyfish.framework.domain.authorized; + +import com.flyfish.framework.builder.CriteriaBuilder; +import com.flyfish.framework.domain.base.NameLikeQo; +import com.flyfish.framework.domain.po.Department; +import lombok.Getter; +import lombok.Setter; + +import java.util.Collections; +import java.util.List; + +/** + * 带鉴权的查询实体,主要以部门隔绝 + * + * @param + */ +@Getter +@Setter +public abstract class AuthorizedQo extends NameLikeQo { + + /** + * 获取可见的权限ids + * + * @return 结果 + */ + public List getAuthorizedIds() { + if (user instanceof AuthorizedUserDetails) { + return ((AuthorizedUserDetails) user).getAuthorityCodes(); + } + return Collections.singletonList(Department.PUBLIC); + } + + @Override + public CriteriaBuilder criteriaBuilder() { + return super.criteriaBuilder().with("authorizedIds", "authorizeId", CriteriaBuilder.Builders.IN); + } +} diff --git a/flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedUserDetails.java b/flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedUserDetails.java new file mode 100644 index 0000000..25cfe9b --- /dev/null +++ b/flyfish-data/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedUserDetails.java @@ -0,0 +1,18 @@ +package com.flyfish.framework.domain.authorized; + +import java.util.List; + +/** + * 支持授权的用户详情 + * + * @author wangyu + */ +public interface AuthorizedUserDetails { + + /** + * 获取授权codes + * + * @return 结果 + */ + List getAuthorityCodes(); +} diff --git a/flyfish-data/src/main/java/com/flyfish/framework/domain/base/BaseQo.java b/flyfish-data/src/main/java/com/flyfish/framework/domain/base/BaseQo.java index b43ea8d..f315c00 100644 --- a/flyfish-data/src/main/java/com/flyfish/framework/domain/base/BaseQo.java +++ b/flyfish-data/src/main/java/com/flyfish/framework/domain/base/BaseQo.java @@ -2,7 +2,6 @@ package com.flyfish.framework.domain.base; import com.fasterxml.jackson.annotation.JsonIgnore; import com.flyfish.framework.builder.CriteriaBuilder; -import com.flyfish.framework.domain.po.User; import org.springframework.data.domain.Example; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -22,7 +21,7 @@ public class BaseQo implements Qo { protected List result; - protected User user; + protected IUser user; public Qo accept(List result, Pageable pageable) { this.pageable = pageable; @@ -52,7 +51,7 @@ public class BaseQo implements Qo { * @return 结果 */ @Override - public User getUser() { + public IUser getUser() { return user; } @@ -62,7 +61,7 @@ public class BaseQo implements Qo { * @param user 用户数据 */ @Override - public void setUser(User user) { + public void setUser(IUser user) { this.user = user; } diff --git a/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Qo.java b/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Qo.java index c8110e0..efe9cee 100644 --- a/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Qo.java +++ b/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Qo.java @@ -36,12 +36,12 @@ public interface Qo { * * @return 结果 */ - User getUser(); + IUser getUser(); /** * 当前用户 */ - void setUser(User user); + void setUser(IUser user); /** * 获取结果集,用于单例部署时快速封装 diff --git a/flyfish-user/src/main/java/com/flyfish/framework/config/AuthenticationAuditorImpl.java b/flyfish-user/src/main/java/com/flyfish/framework/config/AuthenticationAuditorImpl.java index 26276d0..18adbaa 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/config/AuthenticationAuditorImpl.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/config/AuthenticationAuditorImpl.java @@ -5,7 +5,7 @@ import com.flyfish.framework.domain.po.User; import com.flyfish.framework.enums.UserStatus; import com.flyfish.framework.service.AuthenticationAuditor; import com.flyfish.framework.service.AuthenticationLogger; -import com.flyfish.framework.service.ReactiveUserService; +import com.flyfish.framework.service.UserService; import com.flyfish.framework.transform.ResultDataTransformer; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; @@ -24,7 +24,7 @@ import java.util.Date; public class AuthenticationAuditorImpl extends ResultDataTransformer implements AuthenticationAuditor { @Resource - private ReactiveUserService reactiveUserService; + private UserService userService; @Resource private AuthenticationLogger authenticationLogger; @@ -40,7 +40,7 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements updating.setId(details.getId()); updating.setErrorCount(0); updating.setLastTime(new Date()); - return reactiveUserService.updateSelectiveById(updating).then(authenticationLogger.success(user)); + return userService.updateSelectiveById(updating).then(authenticationLogger.success(user)); } /** @@ -56,7 +56,7 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements .getFormData() .flatMap(data -> { String username = data.getFirst("username"); - Mono userMono = reactiveUserService.findByUsername(username).defaultIfEmpty(emptyUser(username)); + Mono userMono = userService.findByUsername(username).defaultIfEmpty(emptyUser(username)); // 当且仅当为凭据错误,尝试 if (exception instanceof BadCredentialsException) { userMono = userMono.flatMap(user -> { @@ -66,7 +66,7 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements if (updating.getErrorCount() >= 5) { updating.setStatus(UserStatus.LOCKED); } - return reactiveUserService.updateSelectiveById(updating); + return userService.updateSelectiveById(updating); }); } return userMono.flatMap(user -> authenticationLogger.failure(user, exception)); diff --git a/flyfish-user/src/main/java/com/flyfish/framework/config/WebSecurityConfig.java b/flyfish-user/src/main/java/com/flyfish/framework/config/WebSecurityConfig.java index dbb2689..256334a 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/config/WebSecurityConfig.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/config/WebSecurityConfig.java @@ -14,7 +14,7 @@ import com.flyfish.framework.handler.JsonLogoutSuccessHandler; import com.flyfish.framework.initializer.UserInitializer; import com.flyfish.framework.service.AuthenticationAuditor; import com.flyfish.framework.service.AuthenticationLogger; -import com.flyfish.framework.service.ReactiveUserService; +import com.flyfish.framework.service.UserService; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -166,7 +166,7 @@ public class WebSecurityConfig { @Bean @ConditionalOnMissingBean(UserInitializer.class) @SuppressWarnings("all") - public UserInitializer userInitializer(ReactiveUserService userService) { + public UserInitializer userInitializer(UserService userService) { return () -> { UserQo qo = new UserQo(); qo.setType(UserType.SUPER_ADMIN.name()); diff --git a/flyfish-user/src/main/java/com/flyfish/framework/config/audit/ReactiveUserAuditor.java b/flyfish-user/src/main/java/com/flyfish/framework/config/audit/ReactiveUserAuditor.java index 2736dcb..0a895a7 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/config/audit/ReactiveUserAuditor.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/config/audit/ReactiveUserAuditor.java @@ -1,6 +1,5 @@ package com.flyfish.framework.config.audit; -import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.utils.UserUtils; import org.springframework.data.domain.ReactiveAuditorAware; import org.springframework.lang.NonNull; @@ -25,8 +24,7 @@ public class ReactiveUserAuditor implements ReactiveAuditorAware { @NonNull public Mono getCurrentAuditor() { return ReactiveSecurityContextHolder.getContext() - .map(UserUtils::extractUser) - .map(Domain::getName) + .map(UserUtils::extractUserName) .defaultIfEmpty("匿名用户"); } diff --git a/flyfish-user/src/main/java/com/flyfish/framework/config/audit/UserBeanAuditor.java b/flyfish-user/src/main/java/com/flyfish/framework/config/audit/UserBeanAuditor.java index f745cb6..e7d89ff 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/config/audit/UserBeanAuditor.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/config/audit/UserBeanAuditor.java @@ -5,6 +5,7 @@ import com.flyfish.framework.auditor.ReactiveBeanPoster; import com.flyfish.framework.config.constants.UserCacheKeys; import com.flyfish.framework.domain.po.User; import com.flyfish.framework.enums.UserType; +import com.flyfish.framework.service.UserDetailsConverter; import com.flyfish.framework.utils.Assert; import com.flyfish.framework.utils.ReactiveRedisOperations; import com.flyfish.framework.utils.StrengthUtils; @@ -20,6 +21,7 @@ public class UserBeanAuditor implements ReactiveBeanAuditor, ReactiveBeanP private final PasswordEncoder passwordEncoder; private final ReactiveRedisOperations reactiveRedisOperations; + private final UserDetailsConverter userDetailsConverter; /** * 对实体进行审查,并补全相关字段 @@ -55,6 +57,7 @@ public class UserBeanAuditor implements ReactiveBeanAuditor, ReactiveBeanP @Override public Mono post(User data) { // 更新缓存 - return reactiveRedisOperations.del(UserCacheKeys.get(data.getUsername())).then(Mono.just(data)); + return reactiveRedisOperations.set(UserCacheKeys.get(data.getUsername()), + userDetailsConverter.mapToUserDetails(data)).then(Mono.just(data)); } } diff --git a/flyfish-user/src/main/java/com/flyfish/framework/controller/UserController.java b/flyfish-user/src/main/java/com/flyfish/framework/controller/UserController.java index 922d36e..b264fab 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/controller/UserController.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/controller/UserController.java @@ -10,9 +10,10 @@ import com.flyfish.framework.domain.base.IUser; import com.flyfish.framework.domain.po.Role; import com.flyfish.framework.domain.po.User; import com.flyfish.framework.enums.UserStatus; -import com.flyfish.framework.service.ReactiveUserService; +import com.flyfish.framework.service.UserService; import com.flyfish.framework.utils.Assert; import com.flyfish.framework.utils.StrengthUtils; +import com.flyfish.framework.utils.UserUtils; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; @@ -84,21 +85,20 @@ public class UserController extends ReactiveBaseController { } /** - * 更新用户状态,主要更新部门 + * 更新用户状态,主要更新部门,同时更新缓存 * * @param authorize 鉴权 * @return 结果 */ @PatchMapping("/status") public Mono> updateStatus(String authorize) { - ReactiveUserService reactiveService = (ReactiveUserService) this.reactiveService; + UserService reactiveService = (UserService) this.reactiveService; return ReactiveSecurityContextHolder.getContext() - .map(context -> (IUser) context.getAuthentication().getPrincipal()) + .map(UserUtils::extractUserDetails) .flatMap(user -> { - user.setAuthority(authorize); User updating = new User(); updating.setId(user.getId()); - updating.setAuthority(user.getAuthority()); + updating.setAuthority(authorize); return reactiveService.updateSelectiveById(updating); }) .map(Result::ok); diff --git a/flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/AuthorizedController.java b/flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/AuthorizedController.java new file mode 100644 index 0000000..3f70cfc --- /dev/null +++ b/flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/AuthorizedController.java @@ -0,0 +1,125 @@ +package com.flyfish.framework.controller.authorized; + +import com.flyfish.framework.annotations.Operation; +import com.flyfish.framework.bean.Result; +import com.flyfish.framework.bean.SyncVo; +import com.flyfish.framework.configuration.annotations.CurrentUser; +import com.flyfish.framework.configuration.annotations.PagedQuery; +import com.flyfish.framework.configuration.annotations.ValidRequestBody; +import com.flyfish.framework.constant.ReactiveConstants; +import com.flyfish.framework.context.UserContext; +import com.flyfish.framework.controller.SafeController; +import com.flyfish.framework.domain.authorized.AuthorizedDomain; +import com.flyfish.framework.domain.authorized.AuthorizedQo; +import com.flyfish.framework.domain.po.User; +import com.flyfish.framework.service.BaseReactiveService; +import com.flyfish.framework.service.BaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * 通用RESTful的控制器,用于动态提供基础的RESTful接口 + * + * @author wangyu + * @create 2017-06-15 8:48 + */ +public abstract class AuthorizedController> implements SafeController { + + @Autowired + protected BaseService service; + @Autowired(required = false) + protected BaseReactiveService reactiveService; + @Autowired + protected UserContext userContext; + + @SuppressWarnings("unchecked") + public > S getService() { + return (S) service; + } + + @GetMapping("/exists") + public Result exists(@PagedQuery Q qo) { + return Result.accept(service.count(qo) != 0); + } + + @GetMapping("/count") + public Result count(@PagedQuery Q qo) { + return Result.accept(service.count(qo)); + } + + @PostMapping("") + @Operation.Create + public Result create(@ValidRequestBody T entity, @CurrentUser User user) { + userContext.setUser(user); + return Result.accept(service.create(entity)); + } + + @GetMapping("{id}") + public Result get(@PathVariable String id) { + return service.getById(id).map(Result::accept).orElse(Result.notFound()); + } + + @PutMapping("{id}") + @Operation.Update + public Result update(@ValidRequestBody T entity, @CurrentUser User user) { + userContext.setUser(user); + return Result.accept(service.updateSelectiveById(entity)); + } + + @PatchMapping("{id}") + @Operation.Update + public Result patch(@RequestBody T entity, @CurrentUser User user) { + userContext.setUser(user); + return Result.accept(service.updateSelectiveById(entity)); + } + + @PutMapping("") + @Operation.UpdateAll + public Result> updateList(@RequestBody List list, @CurrentUser User user) { + userContext.setUser(user); + return Result.accept(service.updateBatch(list)); + } + + @PutMapping("/sync") + @Operation.Sync + public Result> syncList(@RequestBody List list, @CurrentUser User user) { + userContext.setUser(user); + return Result.accept(service.sync(list)); + } + + @DeleteMapping("{id}") + @Operation.Delete + public Result remove(@PathVariable List id, @CurrentUser User user) { + userContext.setUser(user); + service.deleteBatchByIds(id); + return Result.ok(); + } + + @GetMapping("/all") + public Result> all(@PagedQuery Q qo) { + if (qo.isEmpty()) { + return Result.accept(service.getAll()); + } + return Result.accept(service.getList(qo)); + } + + @GetMapping("") + public Result> list(@PagedQuery Q qo) { + if (null != qo.getPageable()) { + return Result.accept(service.getPageList(qo)); + } + return Result.accept(service.getList(qo)); + } + + + @PutMapping(value = "{id}", headers = ReactiveConstants.USE_REACTIVE) + public Mono> reactiveUpdate(@ValidRequestBody T entity) { + return reactiveService.updateById(entity) + .map(Result::accept) + .defaultIfEmpty(Result.notFound()); + } + +} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/ReactiveAuthorizedController.java b/flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/ReactiveAuthorizedController.java new file mode 100644 index 0000000..25f3c67 --- /dev/null +++ b/flyfish-user/src/main/java/com/flyfish/framework/controller/authorized/ReactiveAuthorizedController.java @@ -0,0 +1,100 @@ +package com.flyfish.framework.controller.authorized; + +import com.flyfish.framework.annotations.Operation; +import com.flyfish.framework.bean.Result; +import com.flyfish.framework.bean.SyncVo; +import com.flyfish.framework.configuration.annotations.PagedQuery; +import com.flyfish.framework.configuration.annotations.ValidRequestBody; +import com.flyfish.framework.controller.SafeController; +import com.flyfish.framework.domain.authorized.AuthorizedDomain; +import com.flyfish.framework.domain.authorized.AuthorizedQo; +import com.flyfish.framework.service.BaseReactiveService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.util.CastUtils; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * 多租户带授权的控制器 + * + * @param 实体泛型 + * @param 查询实体泛型 + */ +public abstract class ReactiveAuthorizedController> implements SafeController { + + @Autowired + protected BaseReactiveService reactiveService; + + public > S getService() { + return CastUtils.cast(reactiveService); + } + + @GetMapping("/exists") + public Mono> exists(@PagedQuery Q qo) { + return reactiveService.exists(qo).map(Result::accept); + } + + @GetMapping("/count") + public Mono> count(@PagedQuery Q qo) { + return reactiveService.count(qo).map(Result::accept); + } + + @PostMapping("") + @Operation.Create + public Mono> create(@ValidRequestBody T entity) { + return reactiveService.create(entity).map(Result::accept); + } + + @GetMapping("{id}") + public Mono> get(@PathVariable String id) { + return reactiveService.getById(id).map(Result::accept).defaultIfEmpty(Result.notFound()); + } + + @PutMapping("{id}") + @Operation.Update + public Mono> update(@ValidRequestBody T entity) { + return reactiveService.updateSelectiveById(entity).map(Result::accept).defaultIfEmpty(Result.notFound()); + } + + @PatchMapping("{id}") + @Operation.Update + public Mono> patch(@RequestBody T entity) { + return reactiveService.updateSelectiveById(entity).map(Result::accept).defaultIfEmpty(Result.notFound()); + } + + @PutMapping("") + @Operation.UpdateAll + public Mono>> updateList(@RequestBody List list) { + return reactiveService.updateBatch(list).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList()); + } + + @PutMapping("/sync") + @Operation.Sync + public Mono>> syncList(@RequestBody List list) { + return reactiveService.sync(list).map(Result::accept).defaultIfEmpty(Result.accept(SyncVo.builder().build())); + } + + @DeleteMapping("{id}") + @Operation.Delete + public Mono> remove(@PathVariable List id) { + return reactiveService.deleteBatchByIds(id).thenReturn(Result.ok()); + } + + @GetMapping("/all") + public Mono>> all(@PagedQuery Q qo) { + if (qo.isEmpty()) { + return reactiveService.getAll().collectList().map(Result::accept).defaultIfEmpty(Result.emptyList()); + } + return reactiveService.getList(qo).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList()); + } + + @GetMapping("") + public Mono>> list(@PagedQuery Q qo) { + if (null != qo.getPageable() && qo.getPageable().isPaged()) { + return reactiveService.getPageList(qo).map(Result::accept).defaultIfEmpty(Result.emptyPage()); + } + return reactiveService.getList(qo).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList()); + } +} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/domain/AdminUserDetails.java b/flyfish-user/src/main/java/com/flyfish/framework/domain/AdminUserDetails.java index ac15c78..c42181f 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/domain/AdminUserDetails.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/domain/AdminUserDetails.java @@ -2,6 +2,7 @@ package com.flyfish.framework.domain; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.flyfish.framework.domain.authorized.AuthorizedUserDetails; import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.IUser; import com.flyfish.framework.domain.po.Department; @@ -30,7 +31,7 @@ import java.util.List; */ @Getter @Setter -public class AdminUserDetails implements UserDetails, IUser { +public class AdminUserDetails implements UserDetails, IUser, AuthorizedUserDetails { private static final long serialVersionUID = -2441854985340378429L; @@ -101,6 +102,10 @@ public class AdminUserDetails implements UserDetails, IUser { * 查询冗余,标记用户信息 */ private Object detail; + /** + * 权限code列表 + */ + private List authorityCodes; /** * 判断是否是管理员 diff --git a/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java b/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java deleted file mode 100644 index b76edf9..0000000 --- a/flyfish-user/src/main/java/com/flyfish/framework/domain/authorized/AuthorizedQo.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.flyfish.framework.domain.authorized; - -import com.flyfish.framework.builder.CriteriaBuilder; -import com.flyfish.framework.context.SpringContext; -import com.flyfish.framework.domain.base.NameLikeQo; -import com.flyfish.framework.domain.po.Department; -import com.flyfish.framework.enums.UserType; -import com.flyfish.framework.service.DepartmentService; -import lombok.Getter; -import lombok.Setter; -import lombok.val; -import org.apache.commons.collections4.CollectionUtils; - -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 带鉴权的查询实体,主要以部门隔绝 - * - * @param - */ -@Getter -@Setter -public abstract class AuthorizedQo extends NameLikeQo { - - // 部门服务 - private DepartmentService departmentService; - - /** - * 获取可见的权限ids - * - * @return 结果 - */ - public List getAuthorizedIds() { - if (null != user) { - // 是超级管理员,放行,返回null - if (user.getType() == UserType.SUPER_ADMIN) { - return null; - } - if (CollectionUtils.isNotEmpty(user.getDepartments())) { - val departs = user.getDepartments().stream().map(Department::getId) - .collect(Collectors.toList()); - val result = getSubAuthorities(departs); - if (CollectionUtils.isNotEmpty(result)) { - return result; - } - } - } - return Collections.singletonList(Department.PUBLIC); - } - - @Override - public CriteriaBuilder criteriaBuilder() { - return super.criteriaBuilder().with("authorizedIds", "authorizeId", CriteriaBuilder.Builders.IN); - } - - private List getSubAuthorities(List parents) { - if (null == departmentService) { - departmentService = SpringContext.getBean(DepartmentService.class); - } - return departmentService.getSubCodes(parents); - } -} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java b/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java index 9b49e67..07076c6 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/service/DepartmentService.java @@ -2,14 +2,14 @@ package com.flyfish.framework.service; import com.flyfish.framework.domain.po.Department; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl; -import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; import javax.annotation.Resource; import java.util.List; -import java.util.stream.Collectors; /** * 部门服务 @@ -20,17 +20,16 @@ import java.util.stream.Collectors; public class DepartmentService extends BaseReactiveServiceImpl { @Resource - private MongoOperations mongoOperations; + private ReactiveMongoOperations reactiveMongoOperations; /** * 获取子部门列表 * * @return 结果 */ - public List getSubCodes(List parents) { + public Mono> getSubCodes(List parents) { Query query = Query.query(Criteria.where("parentId").in(parents)); query.fields().include("_id"); - return mongoOperations.find(query, Department.class).stream().map(Department::getId) - .collect(Collectors.toList()); + return reactiveMongoOperations.find(query, Department.class).map(Department::getId).collectList(); } } diff --git a/flyfish-user/src/main/java/com/flyfish/framework/service/MongoUserDetailsServiceImpl.java b/flyfish-user/src/main/java/com/flyfish/framework/service/MongoUserDetailsServiceImpl.java index 4357067..ad90286 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/service/MongoUserDetailsServiceImpl.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/service/MongoUserDetailsServiceImpl.java @@ -1,12 +1,10 @@ package com.flyfish.framework.service; import com.flyfish.framework.config.constants.UserCacheKeys; -import com.flyfish.framework.domain.AdminUserDetails; import com.flyfish.framework.domain.base.IUser; import com.flyfish.framework.domain.po.User; import com.flyfish.framework.enums.UserStatus; import com.flyfish.framework.utils.Assert; -import com.flyfish.framework.utils.CopyUtils; import com.flyfish.framework.utils.ReactiveRedisOperations; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.BooleanUtils; @@ -52,7 +50,8 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService { () -> new LockedException("账户已经锁定!请联系管理员修改密码!")); } - private final ReactiveUserService userService; + private final UserService userService; + private final UserDetailsConverter userDetailsConverter; @Resource private ServerSecurityContextRepository contextRepository; @@ -72,27 +71,23 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService { } @Override - public Mono updatePassword(UserDetails userDetails, String s) { - return userService.updateById(((IUser) userDetails).toUser()).map(this::mapToUserDetails); + public Mono updatePassword(UserDetails userDetails, String password) { + return userService.updateById(((IUser) userDetails).toUser()).thenReturn(userDetails); } @Override - public Mono findByUsername(String s) { - String key = UserCacheKeys.get(s); + public Mono findByUsername(String username) { + String key = UserCacheKeys.get(username); // 优先从缓存读取,如果缓存不存在,查询转换后放入缓存 return reactiveRedisOperations.hasKey(key).flatMap(exists -> Boolean.TRUE.equals(exists) ? reactiveRedisOperations.get(key) : - userService.findByUsername(s).flatMap(this::validate).map(this::mapToUserDetails) + userService.findByUsername(username) + .flatMap(this::validate) + .flatMap(userDetailsConverter::mapToUserDetails) .flatMap(detail -> reactiveRedisOperations.set(key, detail).thenReturn(detail)) ) .switchIfEmpty(Mono.defer(() -> Mono.error(new UsernameNotFoundException("用户不存在!")))); } - private UserDetails mapToUserDetails(IUser user) { - AdminUserDetails userDetail = new AdminUserDetails(); - CopyUtils.copyProps(user, userDetail); - return userDetail; - } - /** * 校验 * @@ -117,7 +112,7 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService { public Mono authenticate(UserDetails user, ServerWebExchange exchange) { return loadContext(user) .flatMap(securityContext -> contextRepository.save(exchange, securityContext) - .subscriberContext(ReactiveSecurityContextHolder.withSecurityContext( + .contextWrite(ReactiveSecurityContextHolder.withSecurityContext( Mono.just(securityContext))) .then(Mono.just(securityContext))) .map(SecurityContext::getAuthentication) @@ -156,4 +151,5 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService { .flatMap(context -> contextRepository.save(exchange, context)); } + } diff --git a/flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java b/flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java deleted file mode 100644 index 6ebf3de..0000000 --- a/flyfish-user/src/main/java/com/flyfish/framework/service/ReactiveUserService.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.flyfish.framework.service; - -import com.flyfish.framework.domain.po.User; -import com.flyfish.framework.repository.ReactiveUserRepository; -import com.flyfish.framework.service.impl.BaseReactiveServiceImpl; -import org.springframework.stereotype.Service; -import reactor.core.publisher.Mono; - -/** - * 异步用户service - * - * @author wangyu - */ -@Service -public class ReactiveUserService extends BaseReactiveServiceImpl implements UserFindService { - - /** - * 获取用户数据 - * - * @param username 用户 - * @return 结果 - */ - @Override - public Mono findByUsername(String username) { - return ((ReactiveUserRepository) repository).findByUsername(username); - } - -} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/service/UserDetailsConverter.java b/flyfish-user/src/main/java/com/flyfish/framework/service/UserDetailsConverter.java new file mode 100644 index 0000000..8ed84dc --- /dev/null +++ b/flyfish-user/src/main/java/com/flyfish/framework/service/UserDetailsConverter.java @@ -0,0 +1,51 @@ +package com.flyfish.framework.service; + +import com.flyfish.framework.domain.AdminUserDetails; +import com.flyfish.framework.domain.base.IUser; +import com.flyfish.framework.domain.po.Department; +import com.flyfish.framework.enums.UserType; +import com.flyfish.framework.utils.CopyUtils; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.util.Collections; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class UserDetailsConverter { + + private final DepartmentService departmentService; + + /** + * 将用户映射为用户详情,查询所有权限code + * + * @param user 用户信息 + * @return 结果 + */ + public Mono mapToUserDetails(IUser user) { + AdminUserDetails userDetail = new AdminUserDetails(); + CopyUtils.copyProps(user, userDetail); + userDetail.setAuthorityCodes(Collections.singletonList(Department.PUBLIC)); + if (user.getType() == UserType.SUPER_ADMIN) { + userDetail.setAuthorityCodes(null); + } + if (CollectionUtils.isNotEmpty(user.getDepartments())) { + val departs = user.getDepartments().stream().map(Department::getId) + .collect(Collectors.toList()); + return departmentService.getSubCodes(departs) + .map(codes -> { + if (CollectionUtils.isNotEmpty(codes)) { + userDetail.setAuthorityCodes(ListUtils.union(codes, userDetail.getAuthorityCodes())); + } + return userDetail; + }); + } + return Mono.just(userDetail); + } +} diff --git a/flyfish-user/src/main/java/com/flyfish/framework/service/UserService.java b/flyfish-user/src/main/java/com/flyfish/framework/service/UserService.java index bc56af1..ea794f3 100644 --- a/flyfish-user/src/main/java/com/flyfish/framework/service/UserService.java +++ b/flyfish-user/src/main/java/com/flyfish/framework/service/UserService.java @@ -1,10 +1,28 @@ package com.flyfish.framework.service; import com.flyfish.framework.domain.po.User; -import com.flyfish.framework.service.impl.BaseServiceImpl; +import com.flyfish.framework.repository.ReactiveUserRepository; +import com.flyfish.framework.service.impl.BaseReactiveServiceImpl; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; +/** + * 异步用户service + * + * @author wangyu + */ @Service -public class UserService extends BaseServiceImpl { +public class UserService extends BaseReactiveServiceImpl implements UserFindService { + + /** + * 获取用户数据 + * + * @param username 用户 + * @return 结果 + */ + @Override + public Mono findByUsername(String username) { + return ((ReactiveUserRepository) repository).findByUsername(username); + } } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/PagedQuery.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/PagedQuery.java index 695614e..331a519 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/PagedQuery.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/annotations/PagedQuery.java @@ -13,4 +13,5 @@ import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface PagedQuery { + } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java b/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java index ea705e1..5f7d1fd 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/configuration/resolver/PageQueryArgumentResolver.java @@ -6,6 +6,7 @@ import com.flyfish.framework.utils.UserUtils; import org.springframework.core.MethodParameter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.data.domain.Pageable; +import org.springframework.data.util.CastUtils; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport; @@ -29,6 +30,7 @@ public class PageQueryArgumentResolver extends HandlerMethodArgumentResolverSupp */ private ModelAttributeFilter modelAttributeFilter; + public PageQueryArgumentResolver(ReactiveAdapterRegistry adapterRegistry) { super(adapterRegistry); this.pageableParameterFilter = new PageParameterFilter(); @@ -56,14 +58,14 @@ public class PageQueryArgumentResolver extends HandlerMethodArgumentResolverSupp // 使用spring的默认解析器解析所有变量 return modelAttributeFilter.filter(parameter, bindingContext, exchange).flatMap(qo -> { if (qo instanceof Qo) { - Qo query = (Qo) qo; + Qo query = (Qo) qo; query.setPageable(pageable); return ReactiveSecurityContextHolder.getContext() - .map(UserUtils::extractUser) + .map(UserUtils::extractUserDetails) .map(user -> { query.setUser(user); return query; - }).defaultIfEmpty(query); + }).defaultIfEmpty(CastUtils.cast(query)); } return Mono.just(qo); }); diff --git a/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseReactiveServiceImpl.java b/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseReactiveServiceImpl.java index 4e2a202..63908f5 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseReactiveServiceImpl.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseReactiveServiceImpl.java @@ -3,6 +3,7 @@ package com.flyfish.framework.service.impl; import com.flyfish.framework.auditor.ReactiveBeanAuditor; import com.flyfish.framework.auditor.ReactiveBeanPoster; import com.flyfish.framework.bean.SyncVo; +import com.flyfish.framework.domain.authorized.AuthorizedDomain; import com.flyfish.framework.domain.base.AuditDomain; import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Qo; @@ -42,6 +43,8 @@ public class BaseReactiveServiceImpl implements BaseReactiveSe protected ReactiveBeanPoster poster; @Autowired private ReactiveBeanAuditor operationAuditor; + @Autowired + private ReactiveBeanAuditor authorizeAuditor; /** * 查询 @@ -369,15 +372,20 @@ public class BaseReactiveServiceImpl implements BaseReactiveSe * @param entity 实体 */ protected Mono audit(T entity) { - // 用户审查 - if (entity instanceof AuditDomain) { - return CastUtils.cast(operationAuditor.audit((AuditDomain) entity)); - } - // 自定义审查 + Mono mono = Mono.just(entity); + // 首先自定义审查,可能返回自定义对象 if (auditor != null) { - return auditor.audit(entity); + mono = mono.flatMap(auditor::audit); } - return Mono.just(entity); + // 操作信息审查 + if (entity instanceof AuditDomain) { + mono = CastUtils.cast(mono.cast(AuditDomain.class).flatMap(operationAuditor::audit)); + } + // 权限审查 + if (entity instanceof AuthorizedDomain) { + mono = CastUtils.cast(mono.cast(AuthorizedDomain.class).flatMap(authorizeAuditor::audit)); + } + return mono; } /** diff --git a/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseServiceImpl.java b/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseServiceImpl.java index 9f61bbc..2e5eb1c 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseServiceImpl.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/service/impl/BaseServiceImpl.java @@ -3,6 +3,7 @@ package com.flyfish.framework.service.impl; import com.flyfish.framework.auditor.BeanAuditor; import com.flyfish.framework.auditor.BeanPoster; import com.flyfish.framework.bean.SyncVo; +import com.flyfish.framework.domain.authorized.AuthorizedDomain; import com.flyfish.framework.domain.base.AuditDomain; import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Qo; @@ -35,6 +36,8 @@ public class BaseServiceImpl implements BaseService { protected BeanPoster poster; @Autowired private BeanAuditor operationAuditor; + @Autowired + private BeanAuditor authorizeAuditor; /** * 查询 @@ -341,13 +344,17 @@ public class BaseServiceImpl implements BaseService { * @param entity 实体 */ protected void audit(T entity) { + // 自定义审查 + if (auditor != null) { + auditor.audit(entity); + } // 用户审查 if (entity instanceof AuditDomain) { operationAuditor.audit((AuditDomain) entity); } - // 自定义审查 - if (auditor != null) { - auditor.audit(entity); + // 权限审查 + if (entity instanceof AuthorizedDomain) { + authorizeAuditor.audit((AuthorizedDomain) entity); } } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/utils/UserUtils.java b/flyfish-web/src/main/java/com/flyfish/framework/utils/UserUtils.java index 4c52d93..6edf329 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/utils/UserUtils.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/utils/UserUtils.java @@ -22,6 +22,26 @@ public class UserUtils { return ((IUser) securityContext.getAuthentication().getPrincipal()).toUser(); } + /** + * 解压用户详情 + * + * @param securityContext 上下文 + * @return 结果 + */ + public static IUser extractUserDetails(SecurityContext securityContext) { + return (IUser) securityContext.getAuthentication().getPrincipal(); + } + + /** + * 解压用户名称 + * + * @param securityContext 上下文 + * @return 结果 + */ + public static String extractUserName(SecurityContext securityContext) { + return ((IUser) securityContext.getAuthentication().getPrincipal()).getName(); + } + /** * 转换用户 *