diff --git a/urbanops-framework/urbanops-common/src/main/java/com/zteits/urbanops/framework/common/biz/system/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java b/urbanops-framework/urbanops-common/src/main/java/com/zteits/urbanops/framework/common/biz/system/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java index 96bce82..50070db 100644 --- a/urbanops-framework/urbanops-common/src/main/java/com/zteits/urbanops/framework/common/biz/system/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java +++ b/urbanops-framework/urbanops-common/src/main/java/com/zteits/urbanops/framework/common/biz/system/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java @@ -24,6 +24,15 @@ public class OAuth2AccessTokenCheckRespDTO implements Serializable { */ private Integer userType; /** + * 业务线 + */ + private String busiLine; + + /** + * 公司id + */ + private Long companyId; + /** * 用户信息 */ private Map userInfo; diff --git a/urbanops-framework/urbanops-spring-boot-starter-mybatis/src/main/java/com/zteits/urbanops/framework/mybatis/config/BusinessLineSqlInterceptor.java b/urbanops-framework/urbanops-spring-boot-starter-mybatis/src/main/java/com/zteits/urbanops/framework/mybatis/config/BusinessLineSqlInterceptor.java index d090263..f9ebe12 100644 --- a/urbanops-framework/urbanops-spring-boot-starter-mybatis/src/main/java/com/zteits/urbanops/framework/mybatis/config/BusinessLineSqlInterceptor.java +++ b/urbanops-framework/urbanops-spring-boot-starter-mybatis/src/main/java/com/zteits/urbanops/framework/mybatis/config/BusinessLineSqlInterceptor.java @@ -1,7 +1,9 @@ package com.zteits.urbanops.framework.mybatis.config; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.zteits.urbanops.framework.annotation.ProcessBusinessLine; +import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; @@ -16,6 +18,7 @@ import org.apache.ibatis.session.RowBounds; import org.springframework.stereotype.Component; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.HashSet; import java.util.Properties; import java.util.Set; @@ -57,7 +60,10 @@ public class BusinessLineSqlInterceptor implements Interceptor { if (!isSkipAnnotation(invocation)) { return invocation.proceed(); } - + String busiLine = SecurityFrameworkUtils.getBusiLine(); + if (StringUtils.isEmpty(busiLine)) { + return invocation.proceed(); + } // 1. 解析拦截参数 Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; @@ -85,8 +91,7 @@ public class BusinessLineSqlInterceptor implements Interceptor { // 3. 仅处理 SELECT/UPDATE/DELETE(INSERT 由自动填充处理) if (SqlCommandType.SELECT.equals(sqlCommandType)) { - Set businessLineSet = new HashSet<>();//UserContextHolder.getBusinessLine(); - businessLineSet.add("yl"); + Set businessLineSet = new HashSet<>(Arrays.asList(busiLine.split(",")));//UserContextHolder.getBusinessLine(); if (!CollectionUtils.isEmpty(businessLineSet)) { // 拼接业务线条件 String newSql = buildSqlWithBusinessLine(originalSql, businessLineSet, sqlCommandType); diff --git a/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/LoginUser.java b/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/LoginUser.java index 3791e63..efbb4f0 100644 --- a/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/LoginUser.java +++ b/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/LoginUser.java @@ -20,6 +20,8 @@ public class LoginUser { public static final String INFO_KEY_NICKNAME = "nickname"; public static final String INFO_KEY_DEPT_ID = "deptId"; + public static final String INFO_KEY_COMPANY_ID = "companyId"; + public static final String INFO_KEY_BUSI_LINE = "busiLine"; /** * 用户编号 @@ -31,6 +33,17 @@ public class LoginUser { * 关联 {@link UserTypeEnum} */ private Integer userType; + + /** + * 业务线 + */ + private String busiLine; + + /** + * 公司id + */ + private Long companyId; + /** * 额外的用户信息 */ diff --git a/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/filter/TokenAuthenticationFilter.java b/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/filter/TokenAuthenticationFilter.java index 6b5dbd2..4af002f 100644 --- a/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/filter/TokenAuthenticationFilter.java +++ b/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/filter/TokenAuthenticationFilter.java @@ -82,7 +82,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { throw new AccessDeniedException("错误的用户类型"); } // 构建登录用户 - return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) + return new LoginUser().setId(accessToken.getUserId()) + .setUserType(accessToken.getUserType()) + .setBusiLine(accessToken.getBusiLine()) + .setCompanyId(accessToken.getCompanyId()) .setInfo(accessToken.getUserInfo()) // 额外的用户信息 .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()) .setExpiresTime(accessToken.getExpiresTime()); diff --git a/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/util/SecurityFrameworkUtils.java b/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/util/SecurityFrameworkUtils.java index 729170e..dbf0c2d 100644 --- a/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/util/SecurityFrameworkUtils.java +++ b/urbanops-framework/urbanops-spring-boot-starter-security/src/main/java/com/zteits/urbanops/framework/security/core/util/SecurityFrameworkUtils.java @@ -114,6 +114,28 @@ public class SecurityFrameworkUtils { } /** + * 获得当前用户的业务线,从上下文中 + * + * @return 部门编号 + */ + @Nullable + public static String getBusiLine() { + LoginUser loginUser = getLoginUser(); + return loginUser != null ? MapUtil.getStr(loginUser.getInfo(), LoginUser.INFO_KEY_BUSI_LINE) : ""; + } + + /** + * 获得当前用户的业务线,从上下文中 + * + * @return 部门编号 + */ + @Nullable + public static Long getCompanyId() { + LoginUser loginUser = getLoginUser(); + return loginUser != null ? MapUtil.getLong(loginUser.getInfo(), LoginUser.INFO_KEY_COMPANY_ID) : null; + } + + /** * 设置当前用户 * * @param loginUser 登录用户 @@ -129,6 +151,8 @@ public class SecurityFrameworkUtils { if (request != null) { WebFrameworkUtils.setLoginUserId(request, loginUser.getId()); WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType()); + WebFrameworkUtils.setLoginUserCompanyId(request, loginUser.getCompanyId()); + WebFrameworkUtils.setLoginUserBusinessLine(request, loginUser.getBusiLine()); } } diff --git a/urbanops-framework/urbanops-spring-boot-starter-web/src/main/java/com/zteits/urbanops/framework/web/core/util/WebFrameworkUtils.java b/urbanops-framework/urbanops-spring-boot-starter-web/src/main/java/com/zteits/urbanops/framework/web/core/util/WebFrameworkUtils.java index af4b05d..a89d45e 100644 --- a/urbanops-framework/urbanops-spring-boot-starter-web/src/main/java/com/zteits/urbanops/framework/web/core/util/WebFrameworkUtils.java +++ b/urbanops-framework/urbanops-spring-boot-starter-web/src/main/java/com/zteits/urbanops/framework/web/core/util/WebFrameworkUtils.java @@ -26,6 +26,10 @@ public class WebFrameworkUtils { public static final String HEADER_TENANT_ID = "tenant-id"; public static final String HEADER_VISIT_TENANT_ID = "visit-tenant-id"; + public static final String REQUEST_ATTRIBUTE_COMPANY_ID = "companyId"; + public static final String REQUEST_ATTRIBUTE_BUSINESS_LINE = "busiLine"; + + /** * 终端的 Header * @@ -67,6 +71,14 @@ public class WebFrameworkUtils { request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId); } + public static void setLoginUserBusinessLine(ServletRequest request, String businessLine) { + request.setAttribute(REQUEST_ATTRIBUTE_BUSINESS_LINE, businessLine); + } + + public static void setLoginUserCompanyId(ServletRequest request, Long companyId) { + request.setAttribute(REQUEST_ATTRIBUTE_COMPANY_ID, companyId); + } + /** * 设置用户类型 * @@ -91,6 +103,14 @@ public class WebFrameworkUtils { return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID); } + public static String getLoginUserBusinessLine(ServletRequest request) { + return (String)request.getAttribute(REQUEST_ATTRIBUTE_BUSINESS_LINE); + } + + public static Long getLoginUserCompanyId(ServletRequest request) { + return (Long)request.getAttribute(REQUEST_ATTRIBUTE_COMPANY_ID); + } + /** * 获得当前用户的类型 * 注意:该方法仅限于 web 相关的 framework 组件使用!!! diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java index f3e20d1..6303055 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java @@ -10,6 +10,7 @@ import lombok.Data; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** * OAuth2 刷新令牌 @@ -40,6 +41,17 @@ public class OAuth2RefreshTokenDO extends TenantBaseDO { * 枚举 {@link UserTypeEnum} */ private Integer userType; + + /** + * 业务线 + */ + private String busiLine; + + /** + * 公司id + */ + private Long companyId; + /** * 客户端编号 * diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/user/AdminUserDO.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/user/AdminUserDO.java index ec957d8..925d29f 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/user/AdminUserDO.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/user/AdminUserDO.java @@ -55,6 +55,18 @@ public class AdminUserDO extends TenantBaseDO { * 部门 ID */ private Long deptId; + + /** + * 公司id(二级部门id) + */ + @TableField(exist = false) + private Long companyId; + + /** + * 业务线: yl-园林;wy-物业:sz-市政;例如:yl,wy' + */ + private String busiLine; + /** * 岗位编号数组 */ diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/auth/AdminAuthServiceImpl.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/auth/AdminAuthServiceImpl.java index 5fb4990..6c807e5 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/auth/AdminAuthServiceImpl.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/auth/AdminAuthServiceImpl.java @@ -206,6 +206,7 @@ public class AdminAuthServiceImpl implements AdminAuthService { CaptchaVO captchaVO = new CaptchaVO(); captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification()); return captchaService.verification(captchaVO); + } private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) { diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptService.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptService.java index 13449cd..3bd853b 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptService.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptService.java @@ -133,4 +133,10 @@ public interface DeptService { */ List getSubDeptList(Long id); + /** + * 查询所有部门信息 + * @return + */ + List getSubDeptAllList(); + } diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptServiceImpl.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptServiceImpl.java index 96b4e9f..8620def 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptServiceImpl.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptServiceImpl.java @@ -244,4 +244,9 @@ public class DeptServiceImpl implements DeptService { public List getSubDeptList(Long id) { return deptMapper.selectList(DeptDO::getParentId,id); } + + @Override + public List getSubDeptAllList() { + return deptMapper.selectList(); + } } diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/oauth2/OAuth2TokenServiceImpl.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/oauth2/OAuth2TokenServiceImpl.java index fa53dd4..1ed8971 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/oauth2/OAuth2TokenServiceImpl.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/oauth2/OAuth2TokenServiceImpl.java @@ -1,6 +1,7 @@ package com.zteits.urbanops.module.system.service.oauth2; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; @@ -14,6 +15,7 @@ import com.zteits.urbanops.framework.security.core.LoginUser; import com.zteits.urbanops.framework.tenant.core.context.TenantContextHolder; import com.zteits.urbanops.framework.tenant.core.util.TenantUtils; import com.zteits.urbanops.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import com.zteits.urbanops.module.system.dal.dataobject.dept.DeptDO; import com.zteits.urbanops.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import com.zteits.urbanops.module.system.dal.dataobject.oauth2.OAuth2ClientDO; import com.zteits.urbanops.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; @@ -21,6 +23,7 @@ import com.zteits.urbanops.module.system.dal.dataobject.user.AdminUserDO; import com.zteits.urbanops.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper; import com.zteits.urbanops.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper; import com.zteits.urbanops.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO; +import com.zteits.urbanops.module.system.service.dept.DeptService; import com.zteits.urbanops.module.system.service.user.AdminUserService; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -31,6 +34,7 @@ import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0; import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.convertSet; @@ -57,6 +61,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { @Lazy // 懒加载,避免循环依赖 private AdminUserService adminUserService; + @Resource + private DeptService deptService; + @Override @Transactional(rollbackFor = Exception.class) public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List scopes) { @@ -173,14 +180,87 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { } private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, OAuth2ClientDO clientDO, List scopes) { + //获取用户信息 + AdminUserDO user = adminUserService.getUser(userId); OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken()) .setUserId(userId).setUserType(userType) + .setCompanyId(getParentDeptId(user.getDeptId())) + .setBusiLine(user.getBusiLine()) .setClientId(clientDO.getClientId()).setScopes(scopes) .setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getRefreshTokenValiditySeconds())); oauth2RefreshTokenMapper.insert(refreshToken); return refreshToken; } + private Long getParentDeptId(Long deptId) { + DeptDO dept = deptService.getDept(deptId); + if (dept == null) { + return null; + } + //顶级部门ID + if(dept.getParentId().equals(0L)) { + return dept.getId(); + } + //二级部门 + if(dept.getParentId().equals(100L)) { + return dept.getId(); + } + //一级以下查二级 + List allDeptList = deptService.getSubDeptAllList(); + if (CollectionUtil.isEmpty(allDeptList)) { + return null; + } + // 构建部门ID → 部门对象的Map(核心:快速根据ID查部门) + Map deptMap = allDeptList.stream() + // 第一个参数:Map 的 Key(取 deptId) + // 第二个参数:Map 的 Value(取 Dept 对象本身) + .collect(Collectors.toMap(DeptDO::getId, DeptDO -> DeptDO)); + + DeptDO findDept = findDeptByTargetParentIdLoop(dept.getParentId(), 100L, deptMap); + return findDept == null ? null : findDept.getId(); + } + + /** + * 循环向上追溯,查找父部门ID等于目标值的部门对象(避免栈溢出) + * @param startDeptId 起始部门ID(指定deptId) + * @param targetParentId 目标parentId(要匹配的父部门ID) + * @param deptIdMap 部门ID映射Map + * @return 匹配的部门对象(无则返回null) + */ + public static DeptDO findDeptByTargetParentIdLoop(Long startDeptId, Long targetParentId, Map deptIdMap) { + // 1. 入参校验 + if (startDeptId == null || targetParentId == null || deptIdMap == null || targetParentId == 0) { + return null; + } + + Long currentDeptId = startDeptId; + while (true) { + // 2. 获取当前部门对象 + DeptDO currentDept = deptIdMap.get(currentDeptId); + if (currentDept == null) { + break; + } + + // 3. 获取当前部门的父ID(父部门的deptId) + Long parentDeptId = currentDept.getParentId(); + // 终止条件:追溯到顶级部门(parentId=0) + if (parentDeptId == 0L) { + break; + } + + // 4. 校验是否匹配目标parentId + if (parentDeptId.equals(targetParentId)) { + return currentDept; // 匹配,返回对象 + } + + // 5. 未匹配,继续追溯父部门 + currentDeptId = currentDept.getParentId(); + } + + // 遍历结束未匹配 + return null; + } + private OAuth2AccessTokenDO convertToAccessToken(OAuth2RefreshTokenDO refreshTokenDO) { OAuth2AccessTokenDO accessTokenDO = BeanUtils.toBean(refreshTokenDO, OAuth2AccessTokenDO.class) .setAccessToken(refreshTokenDO.getRefreshToken()); @@ -203,7 +283,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { if (userType.equals(UserTypeEnum.ADMIN.getValue())) { AdminUserDO user = adminUserService.getUser(userId); return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname()) - .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build(); + .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())) + .put(LoginUser.INFO_KEY_COMPANY_ID, StrUtil.toStringOrNull(user.getCompanyId())) + .put(LoginUser.INFO_KEY_BUSI_LINE, user.getBusiLine()).build(); } else if (userType.equals(UserTypeEnum.MEMBER.getValue())) { // 注意:目前 Member 暂时不读取,可以按需实现 return Collections.emptyMap(); diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/user/AdminUserServiceImpl.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/user/AdminUserServiceImpl.java index 66ede39..eaf6a5b 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/user/AdminUserServiceImpl.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/user/AdminUserServiceImpl.java @@ -42,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.*; +import java.util.stream.Collectors; import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.*; @@ -263,7 +264,7 @@ public class AdminUserServiceImpl implements AdminUserService { @Override public AdminUserDO getUserByUsername(String username) { - return userMapper.selectByUsername(username); + return userMapper.selectByUsername(username); } @Override diff --git a/urbanops-module-system/src/main/resources/mapper/DeptMapper.xml b/urbanops-module-system/src/main/resources/mapper/DeptMapper.xml new file mode 100644 index 0000000..2f1528a --- /dev/null +++ b/urbanops-module-system/src/main/resources/mapper/DeptMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file