✨ 新增应收账单按角色和客户归属的行级数据权限

This commit is contained in:
caojia
2026-10-29 16:42:28 +08:00
parent b091d47f64
commit 02c49e3efe
30 changed files with 587 additions and 72 deletions
@@ -0,0 +1,78 @@
package com.bms.framework.aspectj;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.bms.common.core.domain.entity.SysRole;
import com.bms.common.core.domain.entity.SysUser;
import com.bms.framework.web.service.TokenService;
import com.bms.system.domain.SysUserRole;
/** 授权关系修改提交后,让旧登录态失效;不参与业务 SQL 数据范围计算。 */
@Aspect
@Component
@Order(1)
public class AuthorizationSessionAspect {
private final TokenService tokenService;
public AuthorizationSessionAspect(TokenService tokenService) {
this.tokenService = tokenService;
}
@AfterReturning(pointcut = "execution(* com.bms.system.service.impl.SysUserServiceImpl.updateUser(..))"
+ " || execution(* com.bms.system.service.impl.SysUserServiceImpl.updateUserStatus(..))"
+ " || execution(* com.bms.system.service.impl.SysUserServiceImpl.insertUserAuth(..))"
+ " || execution(* com.bms.system.service.impl.SysUserServiceImpl.deleteUserBy*(..))", returning = "result")
public void userChanged(JoinPoint point, Object result) {
if (result instanceof Number && ((Number) result).intValue() <= 0) return;
Object target = point.getArgs()[0];
Set<Long> users = new HashSet<>();
if (target instanceof SysUser) users.add(((SysUser) target).getUserId());
else if (target instanceof Long[]) users.addAll(Arrays.asList((Long[]) target));
else if (target instanceof Long) users.add((Long) target);
invalidate(users, Set.of());
}
@AfterReturning(pointcut = "execution(* com.bms.system.service.impl.SysRoleServiceImpl.updateRole(..))"
+ " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.updateRoleStatus(..))"
+ " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.deleteRoleBy*(..))"
+ " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.deleteAuthUser*(..))"
+ " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.insertAuthUsers(..))", returning = "result")
public void roleChanged(JoinPoint point, Object result) {
if (result instanceof Number && ((Number) result).intValue() <= 0) return;
Object target = point.getArgs()[0];
Set<Long> users = new HashSet<>();
Set<Long> roles = new HashSet<>();
if (target instanceof SysUserRole) users.add(((SysUserRole) target).getUserId());
else if (point.getArgs().length > 1 && point.getArgs()[1] instanceof Long[])
users.addAll(Arrays.asList((Long[]) point.getArgs()[1]));
else if (target instanceof SysRole) roles.add(((SysRole) target).getRoleId());
else if (target instanceof Long[]) roles.addAll(Arrays.asList((Long[]) target));
else if (target instanceof Long) roles.add((Long) target);
invalidate(users, roles);
}
private void invalidate(Set<Long> users, Set<Long> roles) {
users.remove(null);
Set<Long> roleIds = new HashSet<>(roles);
roleIds.remove(null);
Set<Long> userIds = Set.copyOf(users);
if (userIds.isEmpty() && roleIds.isEmpty()) return;
Runnable action = () -> tokenService.evictAuthorizationSessions(userIds, roleIds);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() { action.run(); }
});
} else {
action.run();
}
}
}
@@ -1,8 +1,6 @@
package com.bms.framework.security.context;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import com.bms.common.core.text.Convert;
import com.bms.common.utils.PermissionContext;
/**
* 权限信息
@@ -11,17 +9,13 @@ import com.bms.common.core.text.Convert;
*/
public class PermissionContextHolder
{
private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";
public static void setContext(String permission)
{
RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
RequestAttributes.SCOPE_REQUEST);
PermissionContext.set(permission);
}
public static String getContext()
{
return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
RequestAttributes.SCOPE_REQUEST));
return PermissionContext.get();
}
}
@@ -3,6 +3,7 @@ package com.bms.framework.web.service;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -231,6 +232,22 @@ public class TokenService
return CacheConstants.LOGIN_TOKEN_KEY + uuid;
}
/** 授权或部门变更后失效受影响会话,避免缓存中的旧角色继续扩大业务范围。 */
public void evictAuthorizationSessions(Set<Long> userIds, Set<Long> roleIds)
{
Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
if (keys == null) return;
for (String key : keys)
{
LoginUser user = redisCache.getCacheObject(key);
if (user == null || user.getUser() == null) continue;
boolean affected = userIds.contains(user.getUserId())
|| (user.getUser().getRoles() != null && user.getUser().getRoles().stream()
.anyMatch(role -> role != null && roleIds.contains(role.getRoleId())));
if (affected) redisCache.deleteObject(key);
}
}
/**
* 角色权限变更后,刷新所有持有该角色的在线用户权限
*