feat:租户隔离策略

This commit is contained in:
wangyu 2021-12-08 23:47:10 +08:00
parent b9f9cb2612
commit a88776119c
7 changed files with 67 additions and 48 deletions

View File

@ -30,7 +30,7 @@ public class TreeQo<T extends Domain> extends NameLikeQo<T> {
CriteriaBuilder<T> builder = super.criteriaBuilder().with("depth");
if (BooleanUtils.isTrue(recursive)) {
builder.with("parentId", "parentIds", Criteria::is)
.with("parentIds", "parentIds", Criteria::is);
.with("parentIds", "parentIds", CriteriaBuilder.Builders.IN);
} else {
builder.with("parentId").with("parentIds", "parentId", CriteriaBuilder.Builders.IN);
}

View File

@ -2,14 +2,14 @@ package com.flyfish.framework.logging.advice;
import com.flyfish.framework.logging.service.LogContext;
import com.flyfish.framework.logging.service.LogManager;
import com.flyfish.framework.utils.UserUtils;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -58,7 +58,7 @@ public class LogAdvice {
context.setError(throwable);
throw throwable;
} finally {
if (!reactive && context.isValid()) {
if (context.isValid() && !reactive) {
context.setResult(result);
logManager.tryLog(context.end());
}
@ -73,19 +73,33 @@ public class LogAdvice {
* @param context 上下文
*/
private Object handleResult(Object result, LogContext context) {
if (!context.isValid()) {
return result;
}
Runnable runnable = () -> {
if (context.isValid()) {
logManager.tryLog(context.end());
}
};
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)
.doOnError(context::setError)
.doOnTerminate(runnable);
} else if (result instanceof Flux) {
return ((Flux<?>) result)
.collectList()
Mono<String> user = ReactiveSecurityContextHolder.getContext()
.map(UserUtils::extractUserName);
return Mono.zip(user, ((Flux<?>) result).collectList())
.map(value -> {
context.setUser(value.getT1());
return value.getT2();
})
.doOnSuccess(context::setResult)
.doOnError(context::setError)
.doOnTerminate(runnable)
@ -95,31 +109,4 @@ public class LogAdvice {
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();
}
}
}

View File

@ -124,7 +124,7 @@ public class LogContext {
}
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();
return this;
}

View File

@ -1,10 +1,18 @@
package com.flyfish.framework.controller;
import com.flyfish.framework.bean.Result;
import com.flyfish.framework.controller.reactive.ReactiveTreeController;
import com.flyfish.framework.domain.AdminUserDetails;
import com.flyfish.framework.domain.DepartmentQo;
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.RestController;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 部分或者校区controller
@ -13,4 +21,20 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/departments")
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);
}
}

View File

@ -28,7 +28,7 @@ public class DepartmentService extends BaseReactiveServiceImpl<Department> {
* @return 结果
*/
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");
return reactiveMongoOperations.find(query, Department.class).map(Department::getId).collectList();
}

View File

@ -38,6 +38,7 @@ public class UserDetailsConverter {
if (CollectionUtils.isNotEmpty(user.getDepartments())) {
val departs = user.getDepartments().stream().map(Department::getId)
.collect(Collectors.toList());
userDetail.setAuthorityCodes(ListUtils.union(departs, userDetail.getAuthorityCodes()));
return departmentService.getSubCodes(departs)
.map(codes -> {
if (CollectionUtils.isNotEmpty(codes)) {

View File

@ -8,7 +8,6 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Collections;
@ -51,18 +50,26 @@ public abstract class ReactiveTreeController<T extends TreeDomain<T>, Q extends
// 第一步查询全部并根据条件筛选
return reactiveService.getList(qo)
.collectList()
.flatMap(filtered -> {
.map(this::makeTree)
.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(), "")));
// 第三步筛选一级树深度
return Flux.fromIterable(filtered)
List<T> roots = filtered.stream()
.filter(item -> null != item && TreeDomain.ROOT.equals(item.getParentId()))
.collectList()
.collect(Collectors.toList());
// 第四步根据父id的map填充根tree
.map(topList -> applyChildren(topList, group));
})
.map(Result::accept);
return applyChildren(roots, group);
}
/**