1. 新增业务数据查询,新增 部门 数据权限规则支持
2. 补全子角色排除父角色管理菜单测试用例
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.framework.business.framework;
|
||||
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.company.CompanyDataPermissionRuleCustomizer;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -10,10 +11,18 @@ import org.springframework.context.annotation.Configuration;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class BusinessDataPermissionConfiguration {
|
||||
@Bean
|
||||
public CompanyDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() {
|
||||
public CompanyDataPermissionRuleCustomizer sysCompanyDataPermissionRuleCustomizer() {
|
||||
return rule -> {
|
||||
// companyId
|
||||
rule.addCompanyColumn("demo_contract", "company_id");
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() {
|
||||
return rule -> {
|
||||
// dept
|
||||
rule.addDeptColumn("demo_contract", "dept_id");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
cn.iocoder.yudao.framework.business.config.YudaoBusinessAutoConfiguration
|
||||
cn.iocoder.yudao.framework.business.config.YudaoBusinessAutoConfiguration
|
||||
cn.iocoder.yudao.framework.business.framework.BusinessDataPermissionConfiguration
|
||||
@@ -0,0 +1,238 @@
|
||||
package cn.iocoder.yudao.framework.business.interceptor;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CompanyDeptInfo;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.security.core.context.SecurityContextHolder.getContext;
|
||||
|
||||
class BusinessHeaderInterceptorTest {
|
||||
|
||||
private BusinessHeaderInterceptor interceptor;
|
||||
private HttpServletRequest request;
|
||||
private HttpServletResponse response;
|
||||
private HandlerMethod handlerMethod;
|
||||
private PrintWriter writer;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
interceptor = new BusinessHeaderInterceptor();
|
||||
request = mock(HttpServletRequest.class);
|
||||
response = mock(HttpServletResponse.class);
|
||||
handlerMethod = mock(HandlerMethod.class);
|
||||
writer = mock(PrintWriter.class);
|
||||
when(response.getWriter()).thenReturn(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:传入的 handler 不是 HandlerMethod,应该直接返回 true
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_NotHandlerMethod() throws Exception {
|
||||
boolean result = interceptor.preHandle(request, response, new Object());
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:handlerMethod.getBean() 不是 BusinessControllerMarker,应该直接返回 true
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_NotBusinessControllerMarker() throws Exception {
|
||||
when(handlerMethod.getBean()).thenReturn(new Object());
|
||||
boolean result = interceptor.preHandle(request, response, handlerMethod);
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:handlerMethod.getBean() 是普通 Controller(未实现 marker 接口),应直接返回 true
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_NormalController() throws Exception {
|
||||
class NormalController {}
|
||||
when(handlerMethod.getBean()).thenReturn(new NormalController());
|
||||
boolean result = interceptor.preHandle(request, response, handlerMethod);
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:marker controller,且 header 无 companyId/deptId,loginUser 有多个公司部门,应该返回 false 并提示 NEED_ADJUST
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_NoCompanyId_MultiCompanyDept() throws Exception {
|
||||
class TestBusinessController implements BusinessControllerMarker {}
|
||||
when(handlerMethod.getBean()).thenReturn(new TestBusinessController());
|
||||
when(request.getHeader("visit-company-id")).thenReturn(null);
|
||||
when(request.getHeader("visit-dept-id")).thenReturn(null);
|
||||
|
||||
// 构造 loginUser,包含多个公司部门
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||
Map<String, String> infoMap = new HashMap<>();
|
||||
infoMap.put(LoginUser.INFO_KEY_COMPANY_DEPT_SET, "[{\"companyId\":1,\"deptId\":2},{\"companyId\":2,\"deptId\":3}]");
|
||||
loginUser.setInfo(infoMap);
|
||||
|
||||
// 通过反射或包可见性设置 getLoginUser 返回
|
||||
setLoginUserForTest(loginUser);
|
||||
|
||||
boolean result = interceptor.preHandle(request, response, handlerMethod);
|
||||
assertFalse(result);
|
||||
verify(writer).write(contains("400"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:header 有 companyId/deptId,loginUser 有多个公司部门,应该正常通过
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_WithCompanyIdDeptId_MultiCompanyDept() throws Exception {
|
||||
class TestBusinessController implements BusinessControllerMarker {}
|
||||
when(handlerMethod.getBean()).thenReturn(new TestBusinessController());
|
||||
when(request.getHeader("visit-company-id")).thenReturn("1");
|
||||
when(request.getHeader("visit-dept-id")).thenReturn("2");
|
||||
|
||||
// 构造 loginUser,包含多个公司部门
|
||||
CompanyDeptInfo deptInfo1 = new CompanyDeptInfo();
|
||||
deptInfo1.setCompanyId(1L);
|
||||
deptInfo1.setDeptId(2L);
|
||||
CompanyDeptInfo deptInfo2 = new CompanyDeptInfo();
|
||||
deptInfo2.setCompanyId(2L);
|
||||
deptInfo2.setDeptId(3L);
|
||||
Set<CompanyDeptInfo> deptSet = new HashSet<>();
|
||||
deptSet.add(deptInfo1);
|
||||
deptSet.add(deptInfo2);
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||
String deptSetJson = "[" +
|
||||
"{\"companyId\":" + deptInfo1.getCompanyId() + ",\"deptId\":" + deptInfo1.getDeptId() + "}," +
|
||||
"{\"companyId\":" + deptInfo2.getCompanyId() + ",\"deptId\":" + deptInfo2.getDeptId() + "}]";
|
||||
Map<String, String> infoMap = new HashMap<>();
|
||||
infoMap.put(LoginUser.INFO_KEY_COMPANY_DEPT_SET, deptSetJson);
|
||||
loginUser.setInfo(infoMap);
|
||||
setLoginUserForTest(loginUser);
|
||||
|
||||
boolean result = interceptor.preHandle(request, response, handlerMethod);
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:header 无 companyId/deptId,loginUser 只有一个公司部门,应该自动填充 header 并通过
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_NoHeader_SingleCompanyDept() throws Exception {
|
||||
class TestBusinessController implements BusinessControllerMarker {}
|
||||
when(handlerMethod.getBean()).thenReturn(new TestBusinessController());
|
||||
when(request.getHeader("visit-company-id")).thenReturn(null);
|
||||
when(request.getHeader("visit-dept-id")).thenReturn(null);
|
||||
|
||||
// 构造 loginUser,只有一个公司且公司下只有一个部门
|
||||
CompanyDeptInfo deptInfo = new CompanyDeptInfo();
|
||||
deptInfo.setCompanyId(100L);
|
||||
deptInfo.setDeptId(200L);
|
||||
Set<CompanyDeptInfo> deptSet = new HashSet<>();
|
||||
deptSet.add(deptInfo);
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||
// 只放一个公司部门
|
||||
String deptSetJson = "[{\"companyId\":" + deptInfo.getCompanyId() + ",\"deptId\":" + deptInfo.getDeptId() + "}]";
|
||||
Map<String, String> infoMap = new HashMap<>();
|
||||
infoMap.put(LoginUser.INFO_KEY_COMPANY_DEPT_SET, deptSetJson);
|
||||
loginUser.setInfo(infoMap);
|
||||
setLoginUserForTest(loginUser);
|
||||
|
||||
boolean result = interceptor.preHandle(request, response, handlerMethod);
|
||||
assertFalse(result);
|
||||
// 可选:verify(request).setAttribute("visit-company-id", String.valueOf(deptInfo.getCompanyId()));
|
||||
// 可选:verify(request).setAttribute("visit-dept-id", String.valueOf(deptInfo.getDeptId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:header 无 companyId/deptId,loginUser 有多个公司部门,应该返回 false 并提示 400
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_NoHeader_MultiCompanyDept() throws Exception {
|
||||
class TestBusinessController implements BusinessControllerMarker {}
|
||||
when(handlerMethod.getBean()).thenReturn(new TestBusinessController());
|
||||
when(request.getHeader("visit-company-id")).thenReturn(null);
|
||||
when(request.getHeader("visit-dept-id")).thenReturn(null);
|
||||
|
||||
// 构造 loginUser,多个公司部门
|
||||
CompanyDeptInfo deptInfo1 = new CompanyDeptInfo();
|
||||
deptInfo1.setCompanyId(1L);
|
||||
deptInfo1.setDeptId(2L);
|
||||
CompanyDeptInfo deptInfo2 = new CompanyDeptInfo();
|
||||
deptInfo2.setCompanyId(2L);
|
||||
deptInfo2.setDeptId(3L);
|
||||
Set<CompanyDeptInfo> deptSet = new HashSet<>();
|
||||
deptSet.add(deptInfo1);
|
||||
deptSet.add(deptInfo2);
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||
String deptSetJson = "[" +
|
||||
"{\"companyId\":" + deptInfo1.getCompanyId() + ",\"deptId\":" + deptInfo1.getDeptId() + "}," +
|
||||
"{\"companyId\":" + deptInfo2.getCompanyId() + ",\"deptId\":" + deptInfo2.getDeptId() + "}]";
|
||||
Map<String, String> infoMap = new HashMap<>();
|
||||
infoMap.put(LoginUser.INFO_KEY_COMPANY_DEPT_SET, deptSetJson);
|
||||
loginUser.setInfo(infoMap);
|
||||
setLoginUserForTest(loginUser);
|
||||
|
||||
boolean result = interceptor.preHandle(request, response, handlerMethod);
|
||||
assertFalse(result);
|
||||
verify(writer).write(contains("400"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用例:header 有错误的 companyId/deptId,loginUser 不包含该公司部门,应该返回 false 并提示 400
|
||||
*/
|
||||
@Test
|
||||
void testPreHandle_HeaderNotMatchUserCompanyDept() throws Exception {
|
||||
class TestBusinessController implements BusinessControllerMarker {}
|
||||
when(handlerMethod.getBean()).thenReturn(new TestBusinessController());
|
||||
when(request.getHeader("visit-company-id")).thenReturn("999");
|
||||
when(request.getHeader("visit-dept-id")).thenReturn("888");
|
||||
|
||||
// 构造 loginUser,只有其他公司部门
|
||||
CompanyDeptInfo deptInfo1 = new CompanyDeptInfo();
|
||||
deptInfo1.setCompanyId(1L);
|
||||
deptInfo1.setDeptId(2L);
|
||||
CompanyDeptInfo deptInfo2 = new CompanyDeptInfo();
|
||||
deptInfo2.setCompanyId(2L);
|
||||
deptInfo2.setDeptId(3L);
|
||||
Set<CompanyDeptInfo> deptSet = new HashSet<>();
|
||||
deptSet.add(deptInfo1);
|
||||
deptSet.add(deptInfo2);
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||
String deptSetJson = "[" +
|
||||
"{\"companyId\":" + deptInfo1.getCompanyId() + ",\"deptId\":" + deptInfo1.getDeptId() + "}," +
|
||||
"{\"companyId\":" + deptInfo2.getCompanyId() + ",\"deptId\":" + deptInfo2.getDeptId() + "}]";
|
||||
Map<String, String> infoMap = new HashMap<>();
|
||||
infoMap.put(LoginUser.INFO_KEY_COMPANY_DEPT_SET, deptSetJson);
|
||||
loginUser.setInfo(infoMap);
|
||||
setLoginUserForTest(loginUser);
|
||||
|
||||
boolean result = interceptor.preHandle(request, response, handlerMethod);
|
||||
assertFalse(result);
|
||||
verify(writer).write(contains("400"));
|
||||
}
|
||||
|
||||
// 工具方法:通过 Spring Security 设置当前登录用户,仅测试环境使用
|
||||
private void setLoginUserForTest(LoginUser loginUser) {
|
||||
// 使用 Spring Security 的 SecurityContextHolder 设置 Authentication
|
||||
getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken(
|
||||
loginUser, null, null
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user