feat:租户隔离策略
This commit is contained in:
parent
b9f9cb2612
commit
a88776119c
@ -30,7 +30,7 @@ public class TreeQo<T extends Domain> extends NameLikeQo<T> {
|
|||||||
CriteriaBuilder<T> builder = super.criteriaBuilder().with("depth");
|
CriteriaBuilder<T> builder = super.criteriaBuilder().with("depth");
|
||||||
if (BooleanUtils.isTrue(recursive)) {
|
if (BooleanUtils.isTrue(recursive)) {
|
||||||
builder.with("parentId", "parentIds", Criteria::is)
|
builder.with("parentId", "parentIds", Criteria::is)
|
||||||
.with("parentIds", "parentIds", Criteria::is);
|
.with("parentIds", "parentIds", CriteriaBuilder.Builders.IN);
|
||||||
} else {
|
} else {
|
||||||
builder.with("parentId").with("parentIds", "parentId", CriteriaBuilder.Builders.IN);
|
builder.with("parentId").with("parentIds", "parentId", CriteriaBuilder.Builders.IN);
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ package com.flyfish.framework.logging.advice;
|
|||||||
|
|
||||||
import com.flyfish.framework.logging.service.LogContext;
|
import com.flyfish.framework.logging.service.LogContext;
|
||||||
import com.flyfish.framework.logging.service.LogManager;
|
import com.flyfish.framework.logging.service.LogManager;
|
||||||
|
import com.flyfish.framework.utils.UserUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import org.reactivestreams.Subscriber;
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
import org.reactivestreams.Subscription;
|
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ public class LogAdvice {
|
|||||||
context.setError(throwable);
|
context.setError(throwable);
|
||||||
throw throwable;
|
throw throwable;
|
||||||
} finally {
|
} finally {
|
||||||
if (!reactive && context.isValid()) {
|
if (context.isValid() && !reactive) {
|
||||||
context.setResult(result);
|
context.setResult(result);
|
||||||
logManager.tryLog(context.end());
|
logManager.tryLog(context.end());
|
||||||
}
|
}
|
||||||
@ -73,19 +73,33 @@ public class LogAdvice {
|
|||||||
* @param context 上下文
|
* @param context 上下文
|
||||||
*/
|
*/
|
||||||
private Object handleResult(Object result, LogContext context) {
|
private Object handleResult(Object result, LogContext context) {
|
||||||
|
if (!context.isValid()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Runnable runnable = () -> {
|
Runnable runnable = () -> {
|
||||||
if (context.isValid()) {
|
if (context.isValid()) {
|
||||||
logManager.tryLog(context.end());
|
logManager.tryLog(context.end());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (result instanceof Mono) {
|
if (result instanceof Mono) {
|
||||||
return ((Mono<?>) result)
|
Mono<String> user = ReactiveSecurityContextHolder.getContext()
|
||||||
|
.map(UserUtils::extractUserName);
|
||||||
|
return Mono.zip(user, (Mono<?>) result)
|
||||||
|
.map(value -> {
|
||||||
|
context.setUser(value.getT1());
|
||||||
|
return value.getT2();
|
||||||
|
})
|
||||||
.doOnSuccess(context::setResult)
|
.doOnSuccess(context::setResult)
|
||||||
.doOnError(context::setError)
|
.doOnError(context::setError)
|
||||||
.doOnTerminate(runnable);
|
.doOnTerminate(runnable);
|
||||||
} else if (result instanceof Flux) {
|
} else if (result instanceof Flux) {
|
||||||
return ((Flux<?>) result)
|
Mono<String> user = ReactiveSecurityContextHolder.getContext()
|
||||||
.collectList()
|
.map(UserUtils::extractUserName);
|
||||||
|
return Mono.zip(user, ((Flux<?>) result).collectList())
|
||||||
|
.map(value -> {
|
||||||
|
context.setUser(value.getT1());
|
||||||
|
return value.getT2();
|
||||||
|
})
|
||||||
.doOnSuccess(context::setResult)
|
.doOnSuccess(context::setResult)
|
||||||
.doOnError(context::setError)
|
.doOnError(context::setError)
|
||||||
.doOnTerminate(runnable)
|
.doOnTerminate(runnable)
|
||||||
@ -95,31 +109,4 @@ public class LogAdvice {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
private static class LogSubscriber implements Subscriber<Object> {
|
|
||||||
|
|
||||||
private final LogContext context;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(Subscription s) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(Object o) {
|
|
||||||
context.setResult(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
context.setError(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
context.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ public class LogContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LogContext end() {
|
public LogContext end() {
|
||||||
this.user = UserContext.sharedContext().map(UserContext::currentUser).map(Domain::getName).orElse("未知");
|
this.user = UserContext.sharedContext().map(UserContext::currentUser).map(Domain::getName).orElse(this.user);
|
||||||
this.endTime = System.currentTimeMillis();
|
this.endTime = System.currentTimeMillis();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
package com.flyfish.framework.controller;
|
package com.flyfish.framework.controller;
|
||||||
|
|
||||||
|
import com.flyfish.framework.bean.Result;
|
||||||
import com.flyfish.framework.controller.reactive.ReactiveTreeController;
|
import com.flyfish.framework.controller.reactive.ReactiveTreeController;
|
||||||
|
import com.flyfish.framework.domain.AdminUserDetails;
|
||||||
import com.flyfish.framework.domain.DepartmentQo;
|
import com.flyfish.framework.domain.DepartmentQo;
|
||||||
import com.flyfish.framework.domain.po.Department;
|
import com.flyfish.framework.domain.po.Department;
|
||||||
|
import com.flyfish.framework.utils.UserUtils;
|
||||||
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部分或者校区controller
|
* 部分或者校区controller
|
||||||
@ -13,4 +21,20 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequestMapping("/departments")
|
@RequestMapping("/departments")
|
||||||
public class DepartmentController extends ReactiveTreeController<Department, DepartmentQo> {
|
public class DepartmentController extends ReactiveTreeController<Department, DepartmentQo> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取有权限的tree
|
||||||
|
*
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@GetMapping("authorized-tree")
|
||||||
|
public Mono<Result<List<Department>>> getAuthorizedTree() {
|
||||||
|
return ReactiveSecurityContextHolder.getContext()
|
||||||
|
.map(UserUtils::extractUserDetails)
|
||||||
|
.flatMap(detail -> {
|
||||||
|
AdminUserDetails details = (AdminUserDetails) detail;
|
||||||
|
return reactiveService.getByIds(details.getAuthorityCodes()).collectList();
|
||||||
|
})
|
||||||
|
.map(this::makeTree)
|
||||||
|
.map(Result::accept);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public class DepartmentService extends BaseReactiveServiceImpl<Department> {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public Mono<List<String>> getSubCodes(List<String> parents) {
|
public Mono<List<String>> getSubCodes(List<String> parents) {
|
||||||
Query query = Query.query(Criteria.where("parentId").in(parents));
|
Query query = Query.query(Criteria.where("parentIds").in(parents));
|
||||||
query.fields().include("_id");
|
query.fields().include("_id");
|
||||||
return reactiveMongoOperations.find(query, Department.class).map(Department::getId).collectList();
|
return reactiveMongoOperations.find(query, Department.class).map(Department::getId).collectList();
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ public class UserDetailsConverter {
|
|||||||
if (CollectionUtils.isNotEmpty(user.getDepartments())) {
|
if (CollectionUtils.isNotEmpty(user.getDepartments())) {
|
||||||
val departs = user.getDepartments().stream().map(Department::getId)
|
val departs = user.getDepartments().stream().map(Department::getId)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
userDetail.setAuthorityCodes(ListUtils.union(departs, userDetail.getAuthorityCodes()));
|
||||||
return departmentService.getSubCodes(departs)
|
return departmentService.getSubCodes(departs)
|
||||||
.map(codes -> {
|
.map(codes -> {
|
||||||
if (CollectionUtils.isNotEmpty(codes)) {
|
if (CollectionUtils.isNotEmpty(codes)) {
|
||||||
|
@ -8,7 +8,6 @@ import org.apache.commons.collections4.CollectionUtils;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -51,20 +50,28 @@ public abstract class ReactiveTreeController<T extends TreeDomain<T>, Q extends
|
|||||||
// 第一步,查询全部,并根据条件筛选
|
// 第一步,查询全部,并根据条件筛选
|
||||||
return reactiveService.getList(qo)
|
return reactiveService.getList(qo)
|
||||||
.collectList()
|
.collectList()
|
||||||
.flatMap(filtered -> {
|
.map(this::makeTree)
|
||||||
// 第二步,根据父id组成map
|
|
||||||
Map<String, List<T>> group = filtered.stream()
|
|
||||||
.collect(Collectors.groupingBy(p -> StringUtils.defaultIfBlank(p.getParentId(), "")));
|
|
||||||
// 第三步,筛选一级树深度
|
|
||||||
return Flux.fromIterable(filtered)
|
|
||||||
.filter(item -> null != item && TreeDomain.ROOT.equals(item.getParentId()))
|
|
||||||
.collectList()
|
|
||||||
// 第四步,根据父id的map填充根tree
|
|
||||||
.map(topList -> applyChildren(topList, group));
|
|
||||||
})
|
|
||||||
.map(Result::accept);
|
.map(Result::accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建一个tree
|
||||||
|
*
|
||||||
|
* @param filtered 过滤后的节点
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
protected List<T> makeTree(List<T> filtered) {
|
||||||
|
// 第二步,根据父id组成map
|
||||||
|
Map<String, List<T>> group = filtered.stream()
|
||||||
|
.collect(Collectors.groupingBy(p -> StringUtils.defaultIfBlank(p.getParentId(), "")));
|
||||||
|
// 第三步,筛选一级树深度
|
||||||
|
List<T> roots = filtered.stream()
|
||||||
|
.filter(item -> null != item && TreeDomain.ROOT.equals(item.getParentId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 第四步,根据父id的map填充根tree
|
||||||
|
return applyChildren(roots, group);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归赋值儿子们
|
* 递归赋值儿子们
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user