Commit 041d22344ba9d18cb60e10fa53d94a9db6f0433b

Authored by 王富生
1 parent 9afefe9a

登录后缓存业务线及公司

Showing 14 changed files with 211 additions and 6 deletions
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 {
24 24 */
25 25 private Integer userType;
26 26 /**
  27 + * 业务线
  28 + */
  29 + private String busiLine;
  30 +
  31 + /**
  32 + * 公司id
  33 + */
  34 + private Long companyId;
  35 + /**
27 36 * 用户信息
28 37 */
29 38 private Map<String, String> userInfo;
... ...
urbanops-framework/urbanops-spring-boot-starter-mybatis/src/main/java/com/zteits/urbanops/framework/mybatis/config/BusinessLineSqlInterceptor.java
1 1 package com.zteits.urbanops.framework.mybatis.config;
2 2  
3 3 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
  4 +import com.baomidou.mybatisplus.core.toolkit.StringUtils;
4 5 import com.zteits.urbanops.framework.annotation.ProcessBusinessLine;
  6 +import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils;
5 7 import lombok.extern.slf4j.Slf4j;
6 8 import org.apache.ibatis.cache.CacheKey;
7 9 import org.apache.ibatis.executor.Executor;
... ... @@ -16,6 +18,7 @@ import org.apache.ibatis.session.RowBounds;
16 18 import org.springframework.stereotype.Component;
17 19  
18 20 import java.lang.reflect.Method;
  21 +import java.util.Arrays;
19 22 import java.util.HashSet;
20 23 import java.util.Properties;
21 24 import java.util.Set;
... ... @@ -57,7 +60,10 @@ public class BusinessLineSqlInterceptor implements Interceptor {
57 60 if (!isSkipAnnotation(invocation)) {
58 61 return invocation.proceed();
59 62 }
60   -
  63 + String busiLine = SecurityFrameworkUtils.getBusiLine();
  64 + if (StringUtils.isEmpty(busiLine)) {
  65 + return invocation.proceed();
  66 + }
61 67 // 1. 解析拦截参数
62 68 Object[] args = invocation.getArgs();
63 69 MappedStatement ms = (MappedStatement) args[0];
... ... @@ -85,8 +91,7 @@ public class BusinessLineSqlInterceptor implements Interceptor {
85 91  
86 92 // 3. 仅处理 SELECT/UPDATE/DELETE(INSERT 由自动填充处理)
87 93 if (SqlCommandType.SELECT.equals(sqlCommandType)) {
88   - Set<String> businessLineSet = new HashSet<>();//UserContextHolder.getBusinessLine();
89   - businessLineSet.add("yl");
  94 + Set<String> businessLineSet = new HashSet<>(Arrays.asList(busiLine.split(",")));//UserContextHolder.getBusinessLine();
90 95 if (!CollectionUtils.isEmpty(businessLineSet)) {
91 96 // 拼接业务线条件
92 97 String newSql = buildSqlWithBusinessLine(originalSql, businessLineSet, sqlCommandType);
... ...
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 {
20 20  
21 21 public static final String INFO_KEY_NICKNAME = "nickname";
22 22 public static final String INFO_KEY_DEPT_ID = "deptId";
  23 + public static final String INFO_KEY_COMPANY_ID = "companyId";
  24 + public static final String INFO_KEY_BUSI_LINE = "busiLine";
23 25  
24 26 /**
25 27 * 用户编号
... ... @@ -31,6 +33,17 @@ public class LoginUser {
31 33 * 关联 {@link UserTypeEnum}
32 34 */
33 35 private Integer userType;
  36 +
  37 + /**
  38 + * 业务线
  39 + */
  40 + private String busiLine;
  41 +
  42 + /**
  43 + * 公司id
  44 + */
  45 + private Long companyId;
  46 +
34 47 /**
35 48 * 额外的用户信息
36 49 */
... ...
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 {
82 82 throw new AccessDeniedException("错误的用户类型");
83 83 }
84 84 // 构建登录用户
85   - return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
  85 + return new LoginUser().setId(accessToken.getUserId())
  86 + .setUserType(accessToken.getUserType())
  87 + .setBusiLine(accessToken.getBusiLine())
  88 + .setCompanyId(accessToken.getCompanyId())
86 89 .setInfo(accessToken.getUserInfo()) // 额外的用户信息
87 90 .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
88 91 .setExpiresTime(accessToken.getExpiresTime());
... ...
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 {
114 114 }
115 115  
116 116 /**
  117 + * 获得当前用户的业务线,从上下文中
  118 + *
  119 + * @return 部门编号
  120 + */
  121 + @Nullable
  122 + public static String getBusiLine() {
  123 + LoginUser loginUser = getLoginUser();
  124 + return loginUser != null ? MapUtil.getStr(loginUser.getInfo(), LoginUser.INFO_KEY_BUSI_LINE) : "";
  125 + }
  126 +
  127 + /**
  128 + * 获得当前用户的业务线,从上下文中
  129 + *
  130 + * @return 部门编号
  131 + */
  132 + @Nullable
  133 + public static Long getCompanyId() {
  134 + LoginUser loginUser = getLoginUser();
  135 + return loginUser != null ? MapUtil.getLong(loginUser.getInfo(), LoginUser.INFO_KEY_COMPANY_ID) : null;
  136 + }
  137 +
  138 + /**
117 139 * 设置当前用户
118 140 *
119 141 * @param loginUser 登录用户
... ... @@ -129,6 +151,8 @@ public class SecurityFrameworkUtils {
129 151 if (request != null) {
130 152 WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
131 153 WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
  154 + WebFrameworkUtils.setLoginUserCompanyId(request, loginUser.getCompanyId());
  155 + WebFrameworkUtils.setLoginUserBusinessLine(request, loginUser.getBusiLine());
132 156 }
133 157 }
134 158  
... ...
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 {
26 26 public static final String HEADER_TENANT_ID = "tenant-id";
27 27 public static final String HEADER_VISIT_TENANT_ID = "visit-tenant-id";
28 28  
  29 + public static final String REQUEST_ATTRIBUTE_COMPANY_ID = "companyId";
  30 + public static final String REQUEST_ATTRIBUTE_BUSINESS_LINE = "busiLine";
  31 +
  32 +
29 33 /**
30 34 * 终端的 Header
31 35 *
... ... @@ -67,6 +71,14 @@ public class WebFrameworkUtils {
67 71 request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId);
68 72 }
69 73  
  74 + public static void setLoginUserBusinessLine(ServletRequest request, String businessLine) {
  75 + request.setAttribute(REQUEST_ATTRIBUTE_BUSINESS_LINE, businessLine);
  76 + }
  77 +
  78 + public static void setLoginUserCompanyId(ServletRequest request, Long companyId) {
  79 + request.setAttribute(REQUEST_ATTRIBUTE_COMPANY_ID, companyId);
  80 + }
  81 +
70 82 /**
71 83 * 设置用户类型
72 84 *
... ... @@ -91,6 +103,14 @@ public class WebFrameworkUtils {
91 103 return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID);
92 104 }
93 105  
  106 + public static String getLoginUserBusinessLine(ServletRequest request) {
  107 + return (String)request.getAttribute(REQUEST_ATTRIBUTE_BUSINESS_LINE);
  108 + }
  109 +
  110 + public static Long getLoginUserCompanyId(ServletRequest request) {
  111 + return (Long)request.getAttribute(REQUEST_ATTRIBUTE_COMPANY_ID);
  112 + }
  113 +
94 114 /**
95 115 * 获得当前用户的类型
96 116 * 注意:该方法仅限于 web 相关的 framework 组件使用!!!
... ...
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java
... ... @@ -10,6 +10,7 @@ import lombok.Data;
10 10  
11 11 import java.time.LocalDateTime;
12 12 import java.util.List;
  13 +import java.util.Map;
13 14  
14 15 /**
15 16 * OAuth2 刷新令牌
... ... @@ -40,6 +41,17 @@ public class OAuth2RefreshTokenDO extends TenantBaseDO {
40 41 * 枚举 {@link UserTypeEnum}
41 42 */
42 43 private Integer userType;
  44 +
  45 + /**
  46 + * 业务线
  47 + */
  48 + private String busiLine;
  49 +
  50 + /**
  51 + * 公司id
  52 + */
  53 + private Long companyId;
  54 +
43 55 /**
44 56 * 客户端编号
45 57 *
... ...
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 {
55 55 * 部门 ID
56 56 */
57 57 private Long deptId;
  58 +
  59 + /**
  60 + * 公司id(二级部门id)
  61 + */
  62 + @TableField(exist = false)
  63 + private Long companyId;
  64 +
  65 + /**
  66 + * 业务线: yl-园林;wy-物业:sz-市政;例如:yl,wy'
  67 + */
  68 + private String busiLine;
  69 +
58 70 /**
59 71 * 岗位编号数组
60 72 */
... ...
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/auth/AdminAuthServiceImpl.java
... ... @@ -206,6 +206,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
206 206 CaptchaVO captchaVO = new CaptchaVO();
207 207 captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification());
208 208 return captchaService.verification(captchaVO);
  209 +
209 210 }
210 211  
211 212 private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
... ...
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptService.java
... ... @@ -133,4 +133,10 @@ public interface DeptService {
133 133 */
134 134 List<DeptDO> getSubDeptList(Long id);
135 135  
  136 + /**
  137 + * 查询所有部门信息
  138 + * @return
  139 + */
  140 + List<DeptDO> getSubDeptAllList();
  141 +
136 142 }
... ...
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/dept/DeptServiceImpl.java
... ... @@ -244,4 +244,9 @@ public class DeptServiceImpl implements DeptService {
244 244 public List<DeptDO> getSubDeptList(Long id) {
245 245 return deptMapper.selectList(DeptDO::getParentId,id);
246 246 }
  247 +
  248 + @Override
  249 + public List<DeptDO> getSubDeptAllList() {
  250 + return deptMapper.selectList();
  251 + }
247 252 }
... ...
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/oauth2/OAuth2TokenServiceImpl.java
1 1 package com.zteits.urbanops.module.system.service.oauth2;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.collection.CollectionUtil;
4 5 import cn.hutool.core.map.MapUtil;
5 6 import cn.hutool.core.util.IdUtil;
6 7 import cn.hutool.core.util.ObjectUtil;
... ... @@ -14,6 +15,7 @@ import com.zteits.urbanops.framework.security.core.LoginUser;
14 15 import com.zteits.urbanops.framework.tenant.core.context.TenantContextHolder;
15 16 import com.zteits.urbanops.framework.tenant.core.util.TenantUtils;
16 17 import com.zteits.urbanops.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
  18 +import com.zteits.urbanops.module.system.dal.dataobject.dept.DeptDO;
17 19 import com.zteits.urbanops.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
18 20 import com.zteits.urbanops.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
19 21 import com.zteits.urbanops.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
... ... @@ -21,6 +23,7 @@ import com.zteits.urbanops.module.system.dal.dataobject.user.AdminUserDO;
21 23 import com.zteits.urbanops.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper;
22 24 import com.zteits.urbanops.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper;
23 25 import com.zteits.urbanops.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO;
  26 +import com.zteits.urbanops.module.system.service.dept.DeptService;
24 27 import com.zteits.urbanops.module.system.service.user.AdminUserService;
25 28 import jakarta.annotation.Resource;
26 29 import org.springframework.context.annotation.Lazy;
... ... @@ -31,6 +34,7 @@ import java.time.LocalDateTime;
31 34 import java.util.Collections;
32 35 import java.util.List;
33 36 import java.util.Map;
  37 +import java.util.stream.Collectors;
34 38  
35 39 import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0;
36 40 import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.convertSet;
... ... @@ -57,6 +61,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
57 61 @Lazy // 懒加载,避免循环依赖
58 62 private AdminUserService adminUserService;
59 63  
  64 + @Resource
  65 + private DeptService deptService;
  66 +
60 67 @Override
61 68 @Transactional(rollbackFor = Exception.class)
62 69 public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes) {
... ... @@ -173,14 +180,87 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
173 180 }
174 181  
175 182 private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, OAuth2ClientDO clientDO, List<String> scopes) {
  183 + //获取用户信息
  184 + AdminUserDO user = adminUserService.getUser(userId);
176 185 OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken())
177 186 .setUserId(userId).setUserType(userType)
  187 + .setCompanyId(getParentDeptId(user.getDeptId()))
  188 + .setBusiLine(user.getBusiLine())
178 189 .setClientId(clientDO.getClientId()).setScopes(scopes)
179 190 .setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getRefreshTokenValiditySeconds()));
180 191 oauth2RefreshTokenMapper.insert(refreshToken);
181 192 return refreshToken;
182 193 }
183 194  
  195 + private Long getParentDeptId(Long deptId) {
  196 + DeptDO dept = deptService.getDept(deptId);
  197 + if (dept == null) {
  198 + return null;
  199 + }
  200 + //顶级部门ID
  201 + if(dept.getParentId().equals(0L)) {
  202 + return dept.getId();
  203 + }
  204 + //二级部门
  205 + if(dept.getParentId().equals(100L)) {
  206 + return dept.getId();
  207 + }
  208 + //一级以下查二级
  209 + List<DeptDO> allDeptList = deptService.getSubDeptAllList();
  210 + if (CollectionUtil.isEmpty(allDeptList)) {
  211 + return null;
  212 + }
  213 + // 构建部门ID → 部门对象的Map(核心:快速根据ID查部门)
  214 + Map<Long, DeptDO> deptMap = allDeptList.stream()
  215 + // 第一个参数:Map 的 Key(取 deptId)
  216 + // 第二个参数:Map 的 Value(取 Dept 对象本身)
  217 + .collect(Collectors.toMap(DeptDO::getId, DeptDO -> DeptDO));
  218 +
  219 + DeptDO findDept = findDeptByTargetParentIdLoop(dept.getParentId(), 100L, deptMap);
  220 + return findDept == null ? null : findDept.getId();
  221 + }
  222 +
  223 + /**
  224 + * 循环向上追溯,查找父部门ID等于目标值的部门对象(避免栈溢出)
  225 + * @param startDeptId 起始部门ID(指定deptId)
  226 + * @param targetParentId 目标parentId(要匹配的父部门ID)
  227 + * @param deptIdMap 部门ID映射Map
  228 + * @return 匹配的部门对象(无则返回null)
  229 + */
  230 + public static DeptDO findDeptByTargetParentIdLoop(Long startDeptId, Long targetParentId, Map<Long, DeptDO> deptIdMap) {
  231 + // 1. 入参校验
  232 + if (startDeptId == null || targetParentId == null || deptIdMap == null || targetParentId == 0) {
  233 + return null;
  234 + }
  235 +
  236 + Long currentDeptId = startDeptId;
  237 + while (true) {
  238 + // 2. 获取当前部门对象
  239 + DeptDO currentDept = deptIdMap.get(currentDeptId);
  240 + if (currentDept == null) {
  241 + break;
  242 + }
  243 +
  244 + // 3. 获取当前部门的父ID(父部门的deptId)
  245 + Long parentDeptId = currentDept.getParentId();
  246 + // 终止条件:追溯到顶级部门(parentId=0)
  247 + if (parentDeptId == 0L) {
  248 + break;
  249 + }
  250 +
  251 + // 4. 校验是否匹配目标parentId
  252 + if (parentDeptId.equals(targetParentId)) {
  253 + return currentDept; // 匹配,返回对象
  254 + }
  255 +
  256 + // 5. 未匹配,继续追溯父部门
  257 + currentDeptId = currentDept.getParentId();
  258 + }
  259 +
  260 + // 遍历结束未匹配
  261 + return null;
  262 + }
  263 +
184 264 private OAuth2AccessTokenDO convertToAccessToken(OAuth2RefreshTokenDO refreshTokenDO) {
185 265 OAuth2AccessTokenDO accessTokenDO = BeanUtils.toBean(refreshTokenDO, OAuth2AccessTokenDO.class)
186 266 .setAccessToken(refreshTokenDO.getRefreshToken());
... ... @@ -203,7 +283,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
203 283 if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
204 284 AdminUserDO user = adminUserService.getUser(userId);
205 285 return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
206   - .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build();
  286 + .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId()))
  287 + .put(LoginUser.INFO_KEY_COMPANY_ID, StrUtil.toStringOrNull(user.getCompanyId()))
  288 + .put(LoginUser.INFO_KEY_BUSI_LINE, user.getBusiLine()).build();
207 289 } else if (userType.equals(UserTypeEnum.MEMBER.getValue())) {
208 290 // 注意:目前 Member 暂时不读取,可以按需实现
209 291 return Collections.emptyMap();
... ...
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;
42 42  
43 43 import java.time.LocalDateTime;
44 44 import java.util.*;
  45 +import java.util.stream.Collectors;
45 46  
46 47 import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception;
47 48 import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.*;
... ... @@ -263,7 +264,7 @@ public class AdminUserServiceImpl implements AdminUserService {
263 264  
264 265 @Override
265 266 public AdminUserDO getUserByUsername(String username) {
266   - return userMapper.selectByUsername(username);
  267 + return userMapper.selectByUsername(username);
267 268 }
268 269  
269 270 @Override
... ...
urbanops-module-system/src/main/resources/mapper/DeptMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="com.zteits.urbanops.module.system.dal.mysql.dept.DeptMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...