refactor permission system
This commit is contained in:
@@ -21,45 +21,45 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
||||
|
||||
STORE_DELETE("STORE:DELETE", "门店删除", false, true),
|
||||
|
||||
CUSTOMER_CREATE("CUSTOMER:CREATE", "客户创建"),
|
||||
CUSTOMER_CREATE("CUSTOMER:CREATE", "客户创建", false, false),
|
||||
|
||||
CUSTOMER_READ("CUSTOMER:READ", "客户读取"),
|
||||
CUSTOMER_READ("CUSTOMER:READ", "客户读取", false, false),
|
||||
|
||||
CUSTOMER_EXPORT("CUSTOMER:EXPORT", "客户导出", true),
|
||||
CUSTOMER_EXPORT("CUSTOMER:EXPORT", "客户导出", true, false),
|
||||
|
||||
CUSTOMER_UPDATE("CUSTOMER:UPDATE", "客户修改"),
|
||||
CUSTOMER_UPDATE("CUSTOMER:UPDATE", "客户修改", false, false),
|
||||
|
||||
CUSTOMER_DELETE("CUSTOMER:DELETE", "客户删除"),
|
||||
CUSTOMER_DELETE("CUSTOMER:DELETE", "客户删除", false, false),
|
||||
|
||||
EVENT_CREATE("EVENT:CREATE", "登记事件创建"),
|
||||
EVENT_CREATE("EVENT:CREATE", "登记事件创建", false, false),
|
||||
|
||||
EVENT_READ("EVENT:READ", "登记事件读取"),
|
||||
EVENT_READ("EVENT:READ", "登记事件读取", false, false),
|
||||
|
||||
EVENT_UPDATE("EVENT:UPDATE", "登记事件修改"),
|
||||
EVENT_UPDATE("EVENT:UPDATE", "登记事件修改", false, false),
|
||||
|
||||
EVENT_DELETE("EVENT:DELETE", "登记事件删除"),
|
||||
EVENT_DELETE("EVENT:DELETE", "登记事件删除", false, false),
|
||||
|
||||
EVENT_RECORD_CREATE("EVENT_RECORD:CREATE", "登记事件记录创建"),
|
||||
EVENT_RECORD_CREATE("EVENT_RECORD:CREATE", "登记事件记录创建", false, false),
|
||||
|
||||
EVENT_RECORD_READ("EVENT_RECORD:READ", "登记事件记录读取"),
|
||||
EVENT_RECORD_READ("EVENT_RECORD:READ", "登记事件记录读取", false, false),
|
||||
|
||||
EVENT_RECORD_EXPORT("EVENT_RECORD:EXPORT", "登记事件记录导出", true),
|
||||
EVENT_RECORD_EXPORT("EVENT_RECORD:EXPORT", "登记事件记录导出", true, false),
|
||||
|
||||
EVENT_RECORD_UPDATE("EVENT_RECORD:UPDATE", "登记事件记录修改"),
|
||||
EVENT_RECORD_UPDATE("EVENT_RECORD:UPDATE", "登记事件记录修改", false, false),
|
||||
|
||||
EVENT_RECORD_DELETE("EVENT_RECORD:DELETE", "登记事件记录删除"),
|
||||
EVENT_RECORD_DELETE("EVENT_RECORD:DELETE", "登记事件记录删除", false, false),
|
||||
|
||||
STAT_READ("STAT:READ", "统计读取"),
|
||||
STAT_READ("STAT:READ", "统计读取", false, false),
|
||||
|
||||
QR_CODE_CREATE("QR_CODE:CREATE", "二维码创建"),
|
||||
QR_CODE_CREATE("QR_CODE:CREATE", "二维码创建", false, false),
|
||||
|
||||
USER_CREATE("USER:CREATE", "用户创建", true),
|
||||
USER_CREATE("USER:CREATE", "用户创建", true, false),
|
||||
|
||||
USER_READ("USER:READ", "用户读取", true),
|
||||
USER_READ("USER:READ", "用户读取", true, false),
|
||||
|
||||
USER_UPDATE("USER:UPDATE", "用户修改", true),
|
||||
USER_UPDATE("USER:UPDATE", "用户修改", true, false),
|
||||
|
||||
USER_DELETE("USER:DELETE", "用户删除", true);
|
||||
USER_DELETE("USER:DELETE", "用户删除", true, false);
|
||||
|
||||
final String value;
|
||||
final String defaultName;
|
||||
@@ -72,14 +72,6 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
||||
@Getter
|
||||
final boolean grantToGlobalManager;
|
||||
|
||||
GaoPermissionCode(String value, String defaultName) {
|
||||
this(value, defaultName, false, false);
|
||||
}
|
||||
|
||||
GaoPermissionCode(String value, String defaultName, boolean grantToStoreManager) {
|
||||
this(value, defaultName, grantToStoreManager, false);
|
||||
}
|
||||
|
||||
GaoPermissionCode(String value, String defaultName, boolean grantToStoreManager, boolean grantToGlobalManager) {
|
||||
this.value = value;
|
||||
this.defaultName = defaultName;
|
||||
@@ -111,4 +103,5 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
||||
public boolean isGrantToAdmin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,9 +16,7 @@ public enum GaoRoleCode implements BuiltinRoleCode {
|
||||
GLOBAL_MANAGER("全局管理员", null),
|
||||
|
||||
/// 店长
|
||||
STORE_MANAGER("店长", GLOBAL_MANAGER.name()),
|
||||
|
||||
EMPLOYEE("员工", STORE_MANAGER.name());
|
||||
STORE_MANAGER("店长", GLOBAL_MANAGER.name());
|
||||
|
||||
final String defaultName;
|
||||
final String parentCode;
|
||||
@@ -42,4 +40,5 @@ public enum GaoRoleCode implements BuiltinRoleCode {
|
||||
public String getParentCode() {
|
||||
return parentCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ package com.imyeyu.api.modules.gao.controller;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.bean.RoleMatchMode;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||
@@ -46,7 +44,6 @@ import java.util.Map;
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-27 14:12
|
||||
@RestController
|
||||
@RequireGaoRole(value = {GaoRoleCode.GLOBAL_MANAGER, GaoRoleCode.STORE_MANAGER, GaoRoleCode.EMPLOYEE}, mode = RoleMatchMode.ANY)
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/gao/customer")
|
||||
public class GaoCustomerController {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.imyeyu.api.modules.gao.controller;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.bean.RoleMatchMode;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoEvent;
|
||||
@@ -30,7 +28,6 @@ import java.util.Map;
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-27 14:13
|
||||
@RestController
|
||||
@RequireGaoRole(value = {GaoRoleCode.GLOBAL_MANAGER, GaoRoleCode.STORE_MANAGER, GaoRoleCode.EMPLOYEE}, mode = RoleMatchMode.ANY)
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/gao/event")
|
||||
public class GaoEventController {
|
||||
|
||||
@@ -2,11 +2,9 @@ package com.imyeyu.api.modules.gao.controller;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.bean.RoleMatchMode;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||
@@ -48,7 +46,6 @@ import java.util.Map;
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-27 14:11
|
||||
@RestController
|
||||
@RequireGaoRole(value = {GaoRoleCode.GLOBAL_MANAGER, GaoRoleCode.STORE_MANAGER, GaoRoleCode.EMPLOYEE}, mode = RoleMatchMode.ANY)
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/gao/event/record")
|
||||
public class GaoEventRecordController {
|
||||
|
||||
@@ -4,7 +4,8 @@ import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.api.modules.user.service.RoleService;
|
||||
import com.imyeyu.api.modules.user.service.AuthorizationScopeService;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.spring.annotation.AOPLog;
|
||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -24,12 +25,13 @@ import java.util.List;
|
||||
@RequestMapping("/gao/role")
|
||||
public class GaoRoleController {
|
||||
|
||||
private final RoleService roleService;
|
||||
private final UserLoginService userLoginService;
|
||||
private final AuthorizationScopeService authorizationScopeService;
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@PostMapping("/available/list")
|
||||
public List<Role> availableList() {
|
||||
return roleService.listByModuleCode(ModuleCode.GAO);
|
||||
return authorizationScopeService.listGrantableRole(userLoginService.getRequireLoginUserId(), ModuleCode.GAO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.imyeyu.api.modules.gao.controller;
|
||||
|
||||
import com.imyeyu.api.bean.RoleMatchMode;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
@@ -34,13 +33,13 @@ import java.util.List;
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/gao/store")
|
||||
@RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
|
||||
public class GaoStoreController {
|
||||
|
||||
private final GaoStoreService service;
|
||||
private final UserLoginService userLoginService;
|
||||
|
||||
@AOPLog
|
||||
@RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
|
||||
@PostMapping("/list")
|
||||
@@ -49,6 +48,7 @@ public class GaoStoreController {
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireGaoRole(GaoRoleCode.STORE_MANAGER)
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
|
||||
@PostMapping("/detail")
|
||||
@@ -66,6 +66,7 @@ public class GaoStoreController {
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireGaoRole(GaoRoleCode.STORE_MANAGER)
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STORE_UPDATE)
|
||||
@PostMapping("/update")
|
||||
@@ -74,6 +75,7 @@ public class GaoStoreController {
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STORE_DELETE)
|
||||
@PostMapping("/delete")
|
||||
@@ -82,6 +84,7 @@ public class GaoStoreController {
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STORE_UPDATE)
|
||||
@PostMapping("/sort")
|
||||
@@ -104,7 +107,6 @@ public class GaoStoreController {
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoRole(value = {GaoRoleCode.GLOBAL_MANAGER, GaoRoleCode.STORE_MANAGER, GaoRoleCode.EMPLOYEE}, mode = RoleMatchMode.ANY)
|
||||
@PostMapping("/user")
|
||||
public GaoStore getLoginStore() {
|
||||
return service.getByUserId(userLoginService.getRequireLoginUserId());
|
||||
|
||||
@@ -39,7 +39,6 @@ import java.util.Map;
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-30 14:15
|
||||
@RestController
|
||||
@RequireGaoRole(GaoRoleCode.STORE_MANAGER)
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/gao/user")
|
||||
public class GaoUserController {
|
||||
|
||||
+3
@@ -65,6 +65,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(GaoCustomer customer) {
|
||||
TimiException.required(customer.getName(), "not found customer.name");
|
||||
@@ -118,6 +119,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void update(GaoCustomer customer) {
|
||||
TimiException.required(customer, "not found customer");
|
||||
@@ -196,6 +198,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void updateWithAttachment(GaoCustomer customer) {
|
||||
update(customer);
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package com.imyeyu.api.modules.gao.service.implement;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.bean.CoreRoleCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoStore;
|
||||
import com.imyeyu.api.modules.gao.service.GaoStoreService;
|
||||
import com.imyeyu.api.modules.user.bean.AuthOwnerType;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||
import com.imyeyu.api.modules.user.mapper.RoleMapper;
|
||||
import com.imyeyu.api.modules.user.mapper.UserRoleMapper;
|
||||
import com.imyeyu.api.modules.user.service.ModuleResourceScopeResolver;
|
||||
import com.imyeyu.api.modules.user.service.RoleHierarchyService;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// GAO 资源范围解析器
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-08-07
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GaoResourceScopeResolver implements ModuleResourceScopeResolver {
|
||||
|
||||
private final RoleMapper roleMapper;
|
||||
private final UserRoleMapper userRoleMapper;
|
||||
private final GaoStoreService gaoStoreService;
|
||||
private final RoleHierarchyService roleHierarchyService;
|
||||
|
||||
@Override
|
||||
public ModuleCode moduleCode() {
|
||||
return ModuleCode.GAO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canManageUser(String operatorUserId, String targetUserId) {
|
||||
if (hasCoreRole(operatorUserId, CoreRoleCode.ADMIN)) {
|
||||
return true;
|
||||
}
|
||||
if (hasGaoRole(operatorUserId, GaoRoleCode.GLOBAL_MANAGER)) {
|
||||
return true;
|
||||
}
|
||||
if (!hasGaoRole(operatorUserId, GaoRoleCode.STORE_MANAGER)) {
|
||||
return false;
|
||||
}
|
||||
GaoStore operatorStore = gaoStoreService.getByUserId(operatorUserId);
|
||||
GaoStore targetStore = gaoStoreService.getByUserId(targetUserId);
|
||||
return operatorStore != null && targetStore != null && operatorStore.getId().equals(targetStore.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canManageRole(String operatorUserId, Role role) {
|
||||
if (hasCoreRole(operatorUserId, CoreRoleCode.ADMIN)) {
|
||||
return true;
|
||||
}
|
||||
if (hasGaoRole(operatorUserId, GaoRoleCode.GLOBAL_MANAGER)) {
|
||||
return true;
|
||||
}
|
||||
if (!hasGaoRole(operatorUserId, GaoRoleCode.STORE_MANAGER)) {
|
||||
return false;
|
||||
}
|
||||
if (canUseOwnerScope(operatorUserId, role.getOwnerType(), role.getOwnerId())) {
|
||||
return true;
|
||||
}
|
||||
return ModuleCode.GAO == role.getModuleCode()
|
||||
&& role.getOwnerType() == AuthOwnerType.MODULE
|
||||
&& (TimiJava.isEmpty(role.getOwnerId()) || ModuleCode.GAO.name().equals(role.getOwnerId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseOwnerScope(String operatorUserId, AuthOwnerType ownerType, String ownerId) {
|
||||
if (hasCoreRole(operatorUserId, CoreRoleCode.ADMIN)) {
|
||||
return ownerType == AuthOwnerType.MODULE && ModuleCode.GAO.name().equals(ownerId) || ownerType == AuthOwnerType.STORE;
|
||||
}
|
||||
if (hasGaoRole(operatorUserId, GaoRoleCode.GLOBAL_MANAGER)) {
|
||||
return ownerType == AuthOwnerType.MODULE && ModuleCode.GAO.name().equals(ownerId) || ownerType == AuthOwnerType.STORE;
|
||||
}
|
||||
if (!hasGaoRole(operatorUserId, GaoRoleCode.STORE_MANAGER) || ownerType != AuthOwnerType.STORE) {
|
||||
return false;
|
||||
}
|
||||
GaoStore store = gaoStoreService.getByUserId(operatorUserId);
|
||||
return store != null && store.getId().equals(ownerId);
|
||||
}
|
||||
|
||||
private boolean hasGaoRole(String userId, GaoRoleCode roleCode) {
|
||||
if (TimiJava.isEmpty(userId)) {
|
||||
return false;
|
||||
}
|
||||
List<String> roleIdList = userRoleMapper.selectByUserIdList(List.of(userId)).stream().map(UserRole::getRoleId).toList();
|
||||
if (TimiJava.isEmpty(roleIdList)) {
|
||||
return false;
|
||||
}
|
||||
// 身份角色只依赖系统、模块级继承,不能依赖当前正在计算的门店作用域
|
||||
List<String> allRoleIdList = roleHierarchyService.listAllRoleIdIncludingChildren(roleIdList);
|
||||
return roleMapper.selectByIdList(allRoleIdList).stream().anyMatch(role -> ModuleCode.GAO == role.getModuleCode() && roleCode.name().equals(role.getCode()));
|
||||
}
|
||||
|
||||
private boolean hasCoreRole(String userId, CoreRoleCode roleCode) {
|
||||
if (TimiJava.isEmpty(userId)) {
|
||||
return false;
|
||||
}
|
||||
List<String> roleIdList = userRoleMapper.selectByUserIdList(List.of(userId)).stream().map(UserRole::getRoleId).toList();
|
||||
if (TimiJava.isEmpty(roleIdList)) {
|
||||
return false;
|
||||
}
|
||||
List<String> allRoleIdList = roleHierarchyService.listAllRoleIdIncludingChildren(roleIdList);
|
||||
return roleMapper.selectByIdList(allRoleIdList).stream().anyMatch(role -> ModuleCode.CORE == role.getModuleCode() && roleCode.name().equals(role.getCode()));
|
||||
}
|
||||
}
|
||||
+3
@@ -50,6 +50,7 @@ public class GaoStoreServiceImplement extends AbstractEntityService<GaoStore, St
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(GaoStore store) {
|
||||
TimiException.required(store, "not found store");
|
||||
@@ -79,6 +80,7 @@ public class GaoStoreServiceImplement extends AbstractEntityService<GaoStore, St
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void update(GaoStore store) {
|
||||
TimiException.required(store, "not found store");
|
||||
@@ -114,6 +116,7 @@ public class GaoStoreServiceImplement extends AbstractEntityService<GaoStore, St
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_STORE_DELETE");
|
||||
|
||||
Reference in New Issue
Block a user