feat:实现用户数据权限细化
This commit is contained in:
parent
23fbdbccf6
commit
0a0b63e480
@ -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
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认选中
|
* 默认选中
|
||||||
*/
|
*/
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否是管理员
|
* 判断是否是管理员
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user