feat:实现用户数据权限细化

This commit is contained in:
wangyu 2021-12-31 10:37:12 +08:00
parent 23fbdbccf6
commit 0a0b63e480
8 changed files with 119 additions and 26 deletions

View File

@ -8,6 +8,7 @@ import lombok.Setter;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* 带鉴权的查询实体主要以部门隔绝 * 带鉴权的查询实体主要以部门隔绝
@ -23,11 +24,11 @@ public abstract class AuthorizedQo<T extends AuthorizedDomain> extends NameLikeQ
* *
* @return 结果 * @return 结果
*/ */
public List<String> getAuthorizedIds() { public Set<String> getAuthorizedIds() {
if (user instanceof AuthorizedUserDetails) { if (user instanceof AuthorizedUserDetails) {
return ((AuthorizedUserDetails) user).getAuthorityCodes(); return ((AuthorizedUserDetails) user).getAuthorityCodes();
} }
return Collections.singletonList(Department.PUBLIC); return Collections.singleton(Department.PUBLIC);
} }
@Override @Override

View File

@ -1,6 +1,6 @@
package com.flyfish.framework.domain.authorized; package com.flyfish.framework.domain.authorized;
import java.util.List; import java.util.Set;
/** /**
* 支持授权的用户详情 * 支持授权的用户详情
@ -14,5 +14,12 @@ public interface AuthorizedUserDetails {
* *
* @return 结果 * @return 结果
*/ */
List<String> getAuthorityCodes(); Set<String> getAuthorityCodes();
/**
* 获取可见部门
*
* @return 结果
*/
Set<String> getVisibleDeparts();
} }

View File

@ -19,6 +19,11 @@ public class Department extends TreeDomain<Department> {
public static final String PUBLIC = "public"; public static final String PUBLIC = "public";
/**
* 部门的完整名称
*/
private String fullName;
/** /**
* 默认选中 * 默认选中
*/ */

View File

@ -1,6 +1,7 @@
package com.flyfish.framework.domain.po; package com.flyfish.framework.domain.po;
import com.flyfish.framework.domain.base.AuditDomain; import com.flyfish.framework.domain.base.AuditDomain;
import com.flyfish.framework.enums.NamedEnum;
import com.flyfish.framework.enums.RoleType; import com.flyfish.framework.enums.RoleType;
import lombok.*; import lombok.*;
import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.DBRef;
@ -46,4 +47,22 @@ public class Role extends AuditDomain {
*/ */
@DBRef @DBRef
private List<Permission> permissions; private List<Permission> permissions;
/**
* 角色拥有的数据权限
*/
private List<Authority> authorities;
/**
* 数据规则权限
*/
@AllArgsConstructor
@Getter
public enum Authority implements NamedEnum {
ADMIN("拥有完全控制权限"), VIEW("查看本部门"), EDIT("编辑本部门"),
VIEW_CHILDREN("查看所有下级"), EDIT_CHILDREN("编辑所有下级");
private final String name;
}
} }

View File

@ -12,6 +12,7 @@ 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 reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -32,7 +33,7 @@ public class DepartmentController extends ReactiveTreeController<Department, Dep
.map(UserUtils::extractUserDetails) .map(UserUtils::extractUserDetails)
.flatMap(detail -> { .flatMap(detail -> {
AdminUserDetails details = (AdminUserDetails) detail; AdminUserDetails details = (AdminUserDetails) detail;
return reactiveService.getByIds(details.getAuthorityCodes()).collectList(); return reactiveService.getByIds(new ArrayList<>(details.getVisibleDeparts())).collectList();
}) })
.map(this::makeTree) .map(this::makeTree)
.map(Result::accept); .map(Result::accept);

View File

@ -19,10 +19,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays; import java.util.*;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/** /**
* 客户端用户详情 * 客户端用户详情
@ -105,7 +102,11 @@ public class AdminUserDetails implements UserDetails, IUser, AuthorizedUserDetai
/** /**
* 权限code列表 * 权限code列表
*/ */
private List<String> authorityCodes; private Set<String> authorityCodes;
/**
* 可见的部门codes
*/
private Set<String> visibleDeparts;
/** /**
* 判断是否是管理员 * 判断是否是管理员

View File

@ -10,6 +10,8 @@ import reactor.core.publisher.Mono;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* 部门服务 * 部门服务
@ -27,9 +29,9 @@ public class DepartmentService extends BaseReactiveServiceImpl<Department> {
* *
* @return 结果 * @return 结果
*/ */
public Mono<List<String>> getSubCodes(List<String> parents) { public Mono<Set<String>> getSubCodes(Set<String> parents) {
Query query = Query.query(Criteria.where("parentIds").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).collect(Collectors.toSet());
} }
} }

View File

@ -3,17 +3,20 @@ package com.flyfish.framework.service;
import com.flyfish.framework.domain.AdminUserDetails; import com.flyfish.framework.domain.AdminUserDetails;
import com.flyfish.framework.domain.base.IUser; import com.flyfish.framework.domain.base.IUser;
import com.flyfish.framework.domain.po.Department; import com.flyfish.framework.domain.po.Department;
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 lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; 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.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.Collections; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -31,22 +34,76 @@ public class UserDetailsConverter {
public Mono<UserDetails> mapToUserDetails(IUser user) { public Mono<UserDetails> mapToUserDetails(IUser user) {
AdminUserDetails userDetail = new AdminUserDetails(); AdminUserDetails userDetail = new AdminUserDetails();
CopyUtils.copyProps(user, userDetail); CopyUtils.copyProps(user, userDetail);
userDetail.setAuthorityCodes(Collections.singletonList(Department.PUBLIC)); userDetail.setAuthorityCodes(Collections.singleton(Department.PUBLIC));
if (user.getType() == UserType.SUPER_ADMIN) { if (user.getType() == UserType.SUPER_ADMIN) {
userDetail.setAuthorityCodes(null); userDetail.setAuthorityCodes(null);
} } else if (CollectionUtils.isNotEmpty(user.getDepartments())) {
if (CollectionUtils.isNotEmpty(user.getDepartments())) { return judgeDeparts(user, userDetail);
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)) {
userDetail.setAuthorityCodes(ListUtils.union(codes, userDetail.getAuthorityCodes()));
}
return userDetail;
});
} }
return Mono.just(userDetail); return Mono.just(userDetail);
} }
/**
* 判断部门包含关系默认看不到本部门的数据却可以看到子部门的
*
* @param user 用户信息
* @param userDetails 用户详情
*/
private Mono<UserDetails> judgeDeparts(IUser user, AdminUserDetails userDetails) {
// 整合数据权限
Set<Role.Authority> authorities = user.getRoles().stream().reduce(new HashSet<>(), (result, item) -> {
// 管理员拥有完全控制权限
if (BooleanUtils.isTrue(item.getAdmin())) {
result.add(Role.Authority.ADMIN);
}
result.addAll(item.getAuthorities());
return result;
}, (a, b) -> a);
// 根据权限组装查询条件
Set<String> departs = mergeDeparts(user.getDepartments());
// 查询所有子部门id
return departmentService.getSubCodes(departs)
.map(codes -> {
// 取出权限便于判定
boolean admin = authorities.contains(Role.Authority.ADMIN);
boolean view = authorities.contains(Role.Authority.VIEW);
boolean viewChildren = authorities.contains(Role.Authority.VIEW_CHILDREN);
// 全部
Set<String> all = new HashSet<>();
// 拥有查看本部门的权限
if (admin || view) {
all.addAll(departs);
}
// 拥有查看所有下级的权限
if (admin || viewChildren) {
all.addAll(codes);
}
// 最终设置权限
if (CollectionUtils.isNotEmpty(all)) {
userDetails.setAuthorityCodes(SetUtils.union(all, userDetails.getAuthorityCodes()));
}
userDetails.setVisibleDeparts(SetUtils.union(codes, departs));
return userDetails;
});
}
/**
* 合并部门有包含关系的部门将被合并
*
* @param departments 部门
* @return 结果
*/
private Set<String> mergeDeparts(List<Department> departments) {
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;
}
} }