feat:完整实现权限隔离
This commit is contained in:
parent
0a0b63e480
commit
38f90de292
@ -3,19 +3,22 @@ package com.flyfish.framework.builder;
|
|||||||
import com.flyfish.framework.context.DateContext;
|
import com.flyfish.framework.context.DateContext;
|
||||||
import com.flyfish.framework.domain.base.Domain;
|
import com.flyfish.framework.domain.base.Domain;
|
||||||
import com.flyfish.framework.domain.base.Qo;
|
import com.flyfish.framework.domain.base.Qo;
|
||||||
|
import com.mongodb.BasicDBList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.collections4.MapUtils;
|
||||||
import org.apache.commons.lang3.ClassUtils;
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor;
|
import java.beans.PropertyDescriptor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,12 +28,11 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
public final class CriteriaBuilder<T extends Domain> {
|
public final class CriteriaBuilder<T extends Domain> {
|
||||||
|
|
||||||
|
private final Map<String, BiFunction<Criteria, Object, Criteria>> functionMap = new HashMap<>();
|
||||||
|
private final Map<String, String> keyMapper = new HashMap<>();
|
||||||
|
private final List<Supplier<Criteria>> criterias = new ArrayList<>();
|
||||||
private Qo<T> qo;
|
private Qo<T> qo;
|
||||||
|
|
||||||
private Map<String, BiFunction<Criteria, Object, Criteria>> functionMap = new HashMap<>();
|
|
||||||
|
|
||||||
private Map<String, String> keyMapper = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造器,接受一个qo
|
* 构造器,接受一个qo
|
||||||
*
|
*
|
||||||
@ -44,6 +46,20 @@ public final class CriteriaBuilder<T extends Domain> {
|
|||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建criteria列表
|
||||||
|
*
|
||||||
|
* @param criteria 多个查询
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static BasicDBList createCriteriaList(Criteria... criteria) {
|
||||||
|
BasicDBList bsonList = new BasicDBList();
|
||||||
|
for (Criteria c : criteria) {
|
||||||
|
bsonList.add(c.getCriteriaObject());
|
||||||
|
}
|
||||||
|
return bsonList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加策略
|
* 添加策略
|
||||||
*
|
*
|
||||||
@ -81,6 +97,17 @@ public final class CriteriaBuilder<T extends Domain> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加自定义条件
|
||||||
|
*
|
||||||
|
* @param function 函数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public CriteriaBuilder<T> with(Supplier<Criteria> function) {
|
||||||
|
this.criterias.add(function);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量导入规则
|
* 批量导入规则
|
||||||
*
|
*
|
||||||
@ -94,11 +121,11 @@ public final class CriteriaBuilder<T extends Domain> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Criteria build() {
|
public Criteria build() {
|
||||||
if (!CollectionUtils.isEmpty(functionMap)) {
|
if (!MapUtils.isEmpty(functionMap)) {
|
||||||
// 键集合
|
// 键集合
|
||||||
Set<String> keySet = functionMap.keySet();
|
Set<String> keySet = functionMap.keySet();
|
||||||
// 建立查询器
|
// 建立查询器
|
||||||
Criteria[] criteria = Arrays.stream(BeanUtils.getPropertyDescriptors(qo.getClass()))
|
List<Criteria> criteria = Arrays.stream(BeanUtils.getPropertyDescriptors(qo.getClass()))
|
||||||
.filter(propertyDescriptor -> keySet.contains(propertyDescriptor.getName()))
|
.filter(propertyDescriptor -> keySet.contains(propertyDescriptor.getName()))
|
||||||
.map(propertyDescriptor -> {
|
.map(propertyDescriptor -> {
|
||||||
try {
|
try {
|
||||||
@ -117,7 +144,13 @@ public final class CriteriaBuilder<T extends Domain> {
|
|||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.toArray(Criteria[]::new);
|
.collect(Collectors.toList());
|
||||||
|
// 添加自定义criteria
|
||||||
|
if (CollectionUtils.isNotEmpty(criterias)) {
|
||||||
|
for (Supplier<Criteria> builder : criterias) {
|
||||||
|
criteria.add(builder.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
return combine(criteria);
|
return combine(criteria);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -165,12 +198,12 @@ public final class CriteriaBuilder<T extends Domain> {
|
|||||||
* @param criteria 结果
|
* @param criteria 结果
|
||||||
* @return 返回
|
* @return 返回
|
||||||
*/
|
*/
|
||||||
private Criteria combine(Criteria[] criteria) {
|
private Criteria combine(List<Criteria> criteria) {
|
||||||
if (criteria.length == 0) {
|
if (criteria.size() == 0) {
|
||||||
return new Criteria();
|
return new Criteria();
|
||||||
}
|
}
|
||||||
if (criteria.length == 1) {
|
if (criteria.size() == 1) {
|
||||||
return criteria[0];
|
return criteria.get(0);
|
||||||
}
|
}
|
||||||
return new Criteria().andOperator(criteria);
|
return new Criteria().andOperator(criteria);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.flyfish.framework.context;
|
||||||
|
|
||||||
|
import com.flyfish.framework.domain.base.IUser;
|
||||||
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步的用户上下文
|
||||||
|
*
|
||||||
|
* @author wangyu
|
||||||
|
*/
|
||||||
|
public class ReactiveUserContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户
|
||||||
|
*
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static Mono<IUser> currentUser() {
|
||||||
|
return ReactiveSecurityContextHolder.getContext()
|
||||||
|
.map(ctx -> (IUser) ctx.getAuthentication().getPrincipal());
|
||||||
|
}
|
||||||
|
}
|
@ -15,4 +15,8 @@ public abstract class AuthorizedDomain extends AuditDomain {
|
|||||||
// 作用域id,一般是部门。用户存储时插入
|
// 作用域id,一般是部门。用户存储时插入
|
||||||
@Property(readonly = true)
|
@Property(readonly = true)
|
||||||
private String authorizeId;
|
private String authorizeId;
|
||||||
|
|
||||||
|
// 是否已发布,已发布的内容,谁都不能修改
|
||||||
|
@Property(readonly = true)
|
||||||
|
private Boolean published = false;
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@ package com.flyfish.framework.domain.authorized;
|
|||||||
import com.flyfish.framework.builder.CriteriaBuilder;
|
import com.flyfish.framework.builder.CriteriaBuilder;
|
||||||
import com.flyfish.framework.domain.base.NameLikeQo;
|
import com.flyfish.framework.domain.base.NameLikeQo;
|
||||||
import com.flyfish.framework.domain.po.Department;
|
import com.flyfish.framework.domain.po.Department;
|
||||||
|
import com.flyfish.framework.enums.UserType;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,12 +20,15 @@ import java.util.Set;
|
|||||||
@Setter
|
@Setter
|
||||||
public abstract class AuthorizedQo<T extends AuthorizedDomain> extends NameLikeQo<T> {
|
public abstract class AuthorizedQo<T extends AuthorizedDomain> extends NameLikeQo<T> {
|
||||||
|
|
||||||
|
// 是否已发布
|
||||||
|
private Boolean published;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取可见的权限ids
|
* 获取可见的权限ids
|
||||||
*
|
*
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public Set<String> getAuthorizedIds() {
|
private Set<String> authorizeIds() {
|
||||||
if (user instanceof AuthorizedUserDetails) {
|
if (user instanceof AuthorizedUserDetails) {
|
||||||
return ((AuthorizedUserDetails) user).getAuthorityCodes();
|
return ((AuthorizedUserDetails) user).getAuthorityCodes();
|
||||||
}
|
}
|
||||||
@ -33,6 +37,17 @@ public abstract class AuthorizedQo<T extends AuthorizedDomain> extends NameLikeQ
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CriteriaBuilder<T> criteriaBuilder() {
|
public CriteriaBuilder<T> criteriaBuilder() {
|
||||||
return super.criteriaBuilder().with("authorizedIds", "authorizeId", CriteriaBuilder.Builders.IN);
|
if (user.getType() == UserType.SUPER_ADMIN) {
|
||||||
|
return super.criteriaBuilder().with("published");
|
||||||
|
}
|
||||||
|
return super.criteriaBuilder()
|
||||||
|
.with(() -> Criteria.where("$or").is(
|
||||||
|
CriteriaBuilder.createCriteriaList(
|
||||||
|
Criteria.where("authorizeId").in(authorizeIds()),
|
||||||
|
Criteria.where("creatorId").is(user.getId())
|
||||||
|
.and("authorizeId").in(((AuthorizedUserDetails) user).getVisibleDeparts())
|
||||||
|
)
|
||||||
|
))
|
||||||
|
.with("published");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.flyfish.framework.domain.authorized;
|
||||||
|
|
||||||
|
import com.flyfish.framework.domain.base.Vo;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权的vo,需要返回权限标识
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public abstract class AuthorizedVo<T extends AuthorizedDomain> implements Vo<T> {
|
||||||
|
|
||||||
|
// 是否是只读数据
|
||||||
|
protected Boolean readonly;
|
||||||
|
}
|
@ -130,6 +130,6 @@ public class BaseQo<T extends Domain> implements Qo<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Sort sorts() {
|
public Sort sorts() {
|
||||||
return Sort.by(Sort.Order.desc("createTime"));
|
return Sort.by(Sort.Order.desc("modifyTime"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package com.flyfish.framework.domain.base;
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.flyfish.framework.annotations.Generation;
|
import com.flyfish.framework.annotations.Generation;
|
||||||
import com.flyfish.framework.annotations.Property;
|
import com.flyfish.framework.annotations.Property;
|
||||||
import com.flyfish.framework.domain.po.User;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
@ -51,7 +50,7 @@ public abstract class Domain implements Po, Named, Serializable {
|
|||||||
@Transient
|
@Transient
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@Property(readonly = true)
|
@Property(readonly = true)
|
||||||
private User currentUser;
|
private IUser currentUser;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
@ -83,7 +83,8 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleReact
|
|||||||
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
|
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
|
||||||
.flatMapMany(querying -> mongoOperations.find(querying,
|
.flatMapMany(querying -> mongoOperations.find(querying,
|
||||||
entityInformation.getJavaType(),
|
entityInformation.getJavaType(),
|
||||||
entityInformation.getCollectionName()));
|
entityInformation.getCollectionName()))
|
||||||
|
.doOnNext(t -> t.setCurrentUser(query.getUser()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,6 +118,7 @@ public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleReact
|
|||||||
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
|
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
|
||||||
.flatMap(querying -> mongoOperations.find(querying.with(pageable),
|
.flatMap(querying -> mongoOperations.find(querying.with(pageable),
|
||||||
entityInformation.getJavaType(), entityInformation.getCollectionName())
|
entityInformation.getJavaType(), entityInformation.getCollectionName())
|
||||||
|
.doOnNext(t -> t.setCurrentUser(query.getUser()))
|
||||||
.collectList()
|
.collectList()
|
||||||
.flatMap(list -> ReactivePageableExecutionUtils.getPage(list, pageable, this.count(query))))
|
.flatMap(list -> ReactivePageableExecutionUtils.getPage(list, pageable, this.count(query))))
|
||||||
.defaultIfEmpty(Page.empty());
|
.defaultIfEmpty(Page.empty());
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
package com.flyfish.framework.utils;
|
||||||
|
|
||||||
|
import com.flyfish.framework.domain.authorized.AuthorizedDomain;
|
||||||
|
import com.flyfish.framework.domain.authorized.AuthorizedVo;
|
||||||
|
import com.flyfish.framework.domain.base.IUser;
|
||||||
|
import com.flyfish.framework.domain.po.Department;
|
||||||
|
import com.flyfish.framework.domain.po.Role;
|
||||||
|
import com.flyfish.framework.enums.UserType;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.springframework.data.util.CastUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门工具类
|
||||||
|
*
|
||||||
|
* @author wangyu
|
||||||
|
*/
|
||||||
|
public final class DepartUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并部门,有包含关系的部门将被合并
|
||||||
|
*
|
||||||
|
* @param departments 部门
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static Set<String> mergeDeparts(List<Department> departments) {
|
||||||
|
if (CollectionUtils.isEmpty(departments)) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
Set<String> departs = departments.stream().map(Department::getId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
List<String> removing = new ArrayList<>();
|
||||||
|
for (Department department : departments) {
|
||||||
|
if (CollectionUtils.containsAny(department.getParentIds(), departs)) {
|
||||||
|
removing.add(department.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removing.forEach(departs::remove);
|
||||||
|
return departs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包装权限,必须调用
|
||||||
|
*
|
||||||
|
* @param item 内容
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static <T> T wrapAuthority(T item, AuthorizedDomain po) {
|
||||||
|
if (item instanceof AuthorizedVo) {
|
||||||
|
AuthorizedVo<?> vo = CastUtils.cast(item);
|
||||||
|
// 已发布的内容,谁都不能修改
|
||||||
|
if (BooleanUtils.isTrue(po.getPublished())) {
|
||||||
|
vo.setReadonly(true);
|
||||||
|
} else {
|
||||||
|
vo.setReadonly(false);
|
||||||
|
// 获取当前用户
|
||||||
|
IUser user = po.getCurrentUser();
|
||||||
|
if (user.getType() != UserType.SUPER_ADMIN) {
|
||||||
|
// 用户所属部门
|
||||||
|
Set<String> userDeparts = DepartUtils.mergeDeparts(user.getDepartments());
|
||||||
|
// 实体归属部门
|
||||||
|
String currentDepart = po.getAuthorizeId();
|
||||||
|
// 用户权限合集
|
||||||
|
Set<Role.Authority> authorities = user.getRoles().stream()
|
||||||
|
.flatMap(role -> null == role.getAuthorities() ? Stream.empty() : role.getAuthorities().stream())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
// 取出权限,便于判定
|
||||||
|
boolean admin = authorities.contains(Role.Authority.ADMIN);
|
||||||
|
boolean edit = authorities.contains(Role.Authority.EDIT);
|
||||||
|
boolean editChildren = authorities.contains(Role.Authority.EDIT_CHILDREN);
|
||||||
|
// 开始判定只读情况,管理员权限或者创建者,均具有读写权限
|
||||||
|
if (!admin && !po.getCreatorId().equals(user.getId())) {
|
||||||
|
vo.setReadonly(!edit && userDeparts.contains(currentDepart) ||
|
||||||
|
!editChildren && !userDeparts.contains(currentDepart));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.flyfish.framework.config.audit;
|
||||||
|
|
||||||
|
import com.flyfish.framework.auditor.ReactiveBeanPoster;
|
||||||
|
import com.flyfish.framework.domain.po.Role;
|
||||||
|
import com.flyfish.framework.service.UserDetailsConverter;
|
||||||
|
import com.flyfish.framework.utils.ReactiveRedisOperations;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色bean后置处理
|
||||||
|
*
|
||||||
|
* @author wangyu
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RoleBeanPoster implements ReactiveBeanPoster<Role> {
|
||||||
|
|
||||||
|
private final ReactiveRedisOperations reactiveRedisOperations;
|
||||||
|
private final UserDetailsConverter userDetailsConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对入库的实体进行审查,并执行额外功能
|
||||||
|
*
|
||||||
|
* @param data 原数据
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Mono<Role> post(Role data) {
|
||||||
|
// 更新缓存
|
||||||
|
return reactiveRedisOperations.del(reactiveRedisOperations.getKeys("user-*")).thenReturn(data);
|
||||||
|
}
|
||||||
|
}
|
@ -5,11 +5,14 @@ import com.flyfish.framework.controller.reactive.ReactiveTreeController;
|
|||||||
import com.flyfish.framework.domain.AdminUserDetails;
|
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.enums.UserType;
|
||||||
import com.flyfish.framework.utils.UserUtils;
|
import com.flyfish.framework.utils.UserUtils;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
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.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -31,10 +34,17 @@ public class DepartmentController extends ReactiveTreeController<Department, Dep
|
|||||||
public Mono<Result<List<Department>>> getAuthorizedTree() {
|
public Mono<Result<List<Department>>> getAuthorizedTree() {
|
||||||
return ReactiveSecurityContextHolder.getContext()
|
return ReactiveSecurityContextHolder.getContext()
|
||||||
.map(UserUtils::extractUserDetails)
|
.map(UserUtils::extractUserDetails)
|
||||||
.flatMap(detail -> {
|
.flatMapMany(detail -> {
|
||||||
AdminUserDetails details = (AdminUserDetails) detail;
|
AdminUserDetails details = (AdminUserDetails) detail;
|
||||||
return reactiveService.getByIds(new ArrayList<>(details.getVisibleDeparts())).collectList();
|
if (details.getType() == UserType.SUPER_ADMIN) {
|
||||||
|
return reactiveService.getAll();
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(details.getVisibleDeparts())) {
|
||||||
|
return reactiveService.getByIds(new ArrayList<>(details.getVisibleDeparts()));
|
||||||
|
}
|
||||||
|
return Flux.empty();
|
||||||
})
|
})
|
||||||
|
.collectList()
|
||||||
.map(this::makeTree)
|
.map(this::makeTree)
|
||||||
.map(Result::accept);
|
.map(Result::accept);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
package com.flyfish.framework.service;
|
package com.flyfish.framework.service;
|
||||||
|
|
||||||
|
import com.flyfish.framework.domain.AdminUserDetails;
|
||||||
|
import com.flyfish.framework.domain.DepartmentQo;
|
||||||
|
import com.flyfish.framework.domain.authorized.AuthorizedUserDetails;
|
||||||
|
import com.flyfish.framework.domain.base.Qo;
|
||||||
import com.flyfish.framework.domain.po.Department;
|
import com.flyfish.framework.domain.po.Department;
|
||||||
|
import com.flyfish.framework.enums.UserType;
|
||||||
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
|
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@ -34,4 +42,39 @@ public class DepartmentService extends BaseReactiveServiceImpl<Department> {
|
|||||||
query.fields().include("_id");
|
query.fields().include("_id");
|
||||||
return reactiveMongoOperations.find(query, Department.class).map(Department::getId).collect(Collectors.toSet());
|
return reactiveMongoOperations.find(query, Department.class).map(Department::getId).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询列表
|
||||||
|
*
|
||||||
|
* @param query 查询
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Flux<Department> getList(Qo<Department> query) {
|
||||||
|
if (query instanceof DepartmentQo) {
|
||||||
|
DepartmentQo qo = (DepartmentQo) query;
|
||||||
|
// 如果是非管理员
|
||||||
|
if (qo.getUser().getType() != UserType.SUPER_ADMIN) {
|
||||||
|
// 使用列表内的部门作为条件
|
||||||
|
AdminUserDetails userDetails = (AdminUserDetails) query.getUser();
|
||||||
|
// 查询根节点下的节点
|
||||||
|
if (Department.ROOT.equals(qo.getParentId())) {
|
||||||
|
qo.setParentId(null);
|
||||||
|
qo.setIds(userDetails.getVisibleDeparts());
|
||||||
|
// 不递归,指定深度,保证单层
|
||||||
|
if (BooleanUtils.isNotTrue(qo.getRecursive())) {
|
||||||
|
// 指定深度
|
||||||
|
int maxDepth = userDetails.getDepartments().stream().max((a, b) -> a.getDepth() - b.getDepth())
|
||||||
|
.map(Department::getDepth)
|
||||||
|
.orElse(0);
|
||||||
|
qo.setDepth(maxDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (null == qo.getParentId() && CollectionUtils.isEmpty(qo.getParentIds())) {
|
||||||
|
qo.setIds(userDetails.getVisibleDeparts());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.getList(query);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,16 @@ import com.flyfish.framework.domain.po.Department;
|
|||||||
import com.flyfish.framework.domain.po.Role;
|
import com.flyfish.framework.domain.po.Role;
|
||||||
import com.flyfish.framework.enums.UserType;
|
import com.flyfish.framework.enums.UserType;
|
||||||
import com.flyfish.framework.utils.CopyUtils;
|
import com.flyfish.framework.utils.CopyUtils;
|
||||||
|
import com.flyfish.framework.utils.DepartUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.val;
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.collections4.ListUtils;
|
|
||||||
import org.apache.commons.collections4.SetUtils;
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -51,16 +49,11 @@ public class UserDetailsConverter {
|
|||||||
*/
|
*/
|
||||||
private Mono<UserDetails> judgeDeparts(IUser user, AdminUserDetails userDetails) {
|
private Mono<UserDetails> judgeDeparts(IUser user, AdminUserDetails userDetails) {
|
||||||
// 整合数据权限
|
// 整合数据权限
|
||||||
Set<Role.Authority> authorities = user.getRoles().stream().reduce(new HashSet<>(), (result, item) -> {
|
Set<Role.Authority> authorities = user.getRoles().stream()
|
||||||
// 管理员拥有完全控制权限
|
.flatMap(role -> null == role.getAuthorities() ? Stream.empty() : role.getAuthorities().stream())
|
||||||
if (BooleanUtils.isTrue(item.getAdmin())) {
|
.collect(Collectors.toSet());
|
||||||
result.add(Role.Authority.ADMIN);
|
|
||||||
}
|
|
||||||
result.addAll(item.getAuthorities());
|
|
||||||
return result;
|
|
||||||
}, (a, b) -> a);
|
|
||||||
// 根据权限组装查询条件
|
// 根据权限组装查询条件
|
||||||
Set<String> departs = mergeDeparts(user.getDepartments());
|
Set<String> departs = DepartUtils.mergeDeparts(user.getDepartments());
|
||||||
// 查询所有子部门id
|
// 查询所有子部门id
|
||||||
return departmentService.getSubCodes(departs)
|
return departmentService.getSubCodes(departs)
|
||||||
.map(codes -> {
|
.map(codes -> {
|
||||||
@ -80,30 +73,25 @@ public class UserDetailsConverter {
|
|||||||
}
|
}
|
||||||
// 最终设置权限
|
// 最终设置权限
|
||||||
if (CollectionUtils.isNotEmpty(all)) {
|
if (CollectionUtils.isNotEmpty(all)) {
|
||||||
userDetails.setAuthorityCodes(SetUtils.union(all, userDetails.getAuthorityCodes()));
|
userDetails.setAuthorityCodes(union(all, userDetails.getAuthorityCodes()));
|
||||||
}
|
}
|
||||||
userDetails.setVisibleDeparts(SetUtils.union(codes, departs));
|
userDetails.setVisibleDeparts(union(codes, departs));
|
||||||
return userDetails;
|
return userDetails;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合并部门,有包含关系的部门将被合并
|
* 链接两个set
|
||||||
*
|
*
|
||||||
* @param departments 部门
|
* @param a 第一个
|
||||||
|
* @param b 第二个
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
private Set<String> mergeDeparts(List<Department> departments) {
|
private Set<String> union(Set<String> a, Set<String> b) {
|
||||||
Set<String> departs = departments.stream().map(Department::getId)
|
Set<String> result = new HashSet<>();
|
||||||
.collect(Collectors.toSet());
|
result.addAll(a);
|
||||||
List<String> removing = new ArrayList<>();
|
result.addAll(b);
|
||||||
for (Department department : departments) {
|
return result;
|
||||||
if (CollectionUtils.containsAny(department.getParentIds(), departs)) {
|
|
||||||
removing.add(department.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removing.forEach(departs::remove);
|
|
||||||
return departs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
package com.flyfish.framework.service;
|
package com.flyfish.framework.service;
|
||||||
|
|
||||||
|
import com.flyfish.framework.domain.UserQo;
|
||||||
|
import com.flyfish.framework.domain.authorized.AuthorizedUserDetails;
|
||||||
|
import com.flyfish.framework.domain.base.Qo;
|
||||||
import com.flyfish.framework.domain.po.User;
|
import com.flyfish.framework.domain.po.User;
|
||||||
|
import com.flyfish.framework.enums.UserType;
|
||||||
import com.flyfish.framework.repository.UserRepository;
|
import com.flyfish.framework.repository.UserRepository;
|
||||||
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
|
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步用户service
|
* 异步用户service
|
||||||
*
|
*
|
||||||
@ -25,4 +33,22 @@ public class UserService extends BaseReactiveServiceImpl<User> implements UserFi
|
|||||||
return ((UserRepository) repository).findByUsername(username);
|
return ((UserRepository) repository).findByUsername(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询,这里使用作用域查询
|
||||||
|
*
|
||||||
|
* @param query 查询实体
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Mono<Page<User>> getPageList(Qo<User> query) {
|
||||||
|
// 非超级管理员,永远返回作用域的部门人员
|
||||||
|
if (query.getUser().getType() != UserType.SUPER_ADMIN) {
|
||||||
|
AuthorizedUserDetails userDetails = (AuthorizedUserDetails) query.getUser();
|
||||||
|
UserQo qo = (UserQo) query;
|
||||||
|
if (CollectionUtils.isEmpty(qo.getDepartments())) {
|
||||||
|
qo.setDepartments(new ArrayList<>(userDetails.getVisibleDeparts()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.getPageList(query);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.flyfish.framework.controller.reactive;
|
package com.flyfish.framework.controller.reactive;
|
||||||
|
|
||||||
import com.flyfish.framework.bean.Result;
|
import com.flyfish.framework.bean.Result;
|
||||||
|
import com.flyfish.framework.configuration.annotations.PagedQuery;
|
||||||
import com.flyfish.framework.domain.tree.RootTreeNode;
|
import com.flyfish.framework.domain.tree.RootTreeNode;
|
||||||
import com.flyfish.framework.domain.tree.TreeDomain;
|
import com.flyfish.framework.domain.tree.TreeDomain;
|
||||||
import com.flyfish.framework.domain.tree.TreeQo;
|
import com.flyfish.framework.domain.tree.TreeQo;
|
||||||
@ -45,7 +46,7 @@ public abstract class ReactiveTreeController<T extends TreeDomain<T>, Q extends
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@GetMapping("tree")
|
@GetMapping("tree")
|
||||||
public Mono<Result<List<T>>> getTree(Q qo) {
|
public Mono<Result<List<T>>> getTree(@PagedQuery Q qo) {
|
||||||
qo.setRecursive(true);
|
qo.setRecursive(true);
|
||||||
// 第一步,查询全部,并根据条件筛选
|
// 第一步,查询全部,并根据条件筛选
|
||||||
return reactiveService.getList(qo)
|
return reactiveService.getList(qo)
|
||||||
|
@ -73,6 +73,16 @@ public class ReactiveRedisOperations {
|
|||||||
return Mono.just(0L);
|
return Mono.just(0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除缓存
|
||||||
|
*
|
||||||
|
* @param key 可以传一个值 或多个
|
||||||
|
*/
|
||||||
|
public Mono<Long> del(Flux<String> key) {
|
||||||
|
return redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================String=============================
|
// ============================String=============================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user