【更新】更新实时刷新数据权限范围及产品readme

This commit is contained in:
俞宝山
2026-03-12 13:31:20 +08:00
parent f256b2f5c7
commit 447c4cad2d
8 changed files with 109 additions and 10 deletions

View File

@@ -8,7 +8,8 @@
SnowySnowyAdmin是国内首个国密前后端分离快速开发平台集成国密加解密插件
软件层面完全符合等保测评要求,同时实现国产化机型、中间件、数据库适配,是您的不二之选!
技术框架与密码结合,让更多的人认识密码,使用密码;更是让前后分离“密”不可分
将国密能力内置于技术框架底层,让密码技术从"专业门槛"变为"开箱即用",真正实现业务安全从底层做起
历经多年开源社区打磨与企业客户实践验证,新版本在大数据处理能力与安全体系方面实现了全面升级。
采用SpringBoot+MybatisPlus+AntDesignVue+Vite 等更多组件及前沿技术开发,注释丰富,代码简洁,开箱即用!
@@ -61,6 +62,15 @@ gitcode下载地址[https://gitcode.com/xiaonuobase/Snowy](https://gitcode.co
文档地址:[https://xiaonuo.vip/doc](https://xiaonuo.vip/doc)
## 商业产品
- 如果开源版本不能满足您的需求,还可以看看我们官方推出的基于开源版开发的商业化产品
| 产品名称 | 演示 | 用途 |
|-------------|------------------------------------------------------|---------------------------------|
| AI智能化零代码开发平台 | [https://alsc.xiaonuo.vip](https://alsc.xiaonuo.vip) | AI智能驱动拖拉拽即可搭建业务系统无需编写一行代码 |
| 国产数据中台 | [https://data.xiaonuo.vip](https://data.xiaonuo.vip) | 覆盖数据采集、存储、治理、安全、资产化、服务全流程的一站式数据管理平台 |
## 快速启动
全栈工程师推荐idea
@@ -240,7 +250,7 @@ QQ技术群732230670已满、685395081
微信技术群:
因群达到200人以上需加微信拉群禁止群内艾特群主及管理员私信提问技术问题无时间精力回答(免开尊口),请群内互动互助才是建群的意义,否则我认为你没有加群的必要
因群达到200人以上需加微信拉群禁止群内艾特群主及管理员私信提问技术问题无时间精力回答请群内互动互助交流技术才是建群的意义
<table>
<tr>
@@ -326,6 +336,6 @@ QQ技术群732230670已满、685395081
- 代码可用于个人项目等接私活或企业项目脚手架使用Snowy全系开源版完全免费
- 二次开发如用于开源竞品请先联系群主沟通,禁止任何变相的二开行为,未经审核视为侵权
- 二次开源不可参与同类竞争,可在其他赛道进行,有好的案例可以提供,我们会挂在本页进行宣传
- 请不要删除和修改Snowy源码头部的版权与作者声明及出处

View File

@@ -22,10 +22,6 @@ export default {
orgPage(data) {
return request('page', data, 'get')
},
// 获取机构列表
orgList(data) {
return request('list', data, 'get')
},
// 获取机构树(懒加载)
orgTree(data) {
return request('tree', data, 'get')

View File

@@ -337,7 +337,7 @@
const isFullTree = ref(false)
// 加载全量树(用于需要展开到指定节点的场景)
const loadFullTree = () => {
return bizUserApi.userOrgTreeSelector({ searchKey: '' }).then((res) => {
return bizUserApi.orgTreeSelector({ searchKey: '' }).then((res) => {
if (res !== null) {
treeData.value = res
// 只有一个根节点时才自动展开
@@ -349,7 +349,7 @@
}
// 加载懒加载树(无需展开到指定节点时使用)
const loadLazyTree = () => {
return bizUserApi.userOrgTreeSelector().then((res) => {
return bizUserApi.orgTreeSelector().then((res) => {
if (res !== null) {
treeData.value = res.map((item) => {
return {
@@ -418,7 +418,7 @@
return
}
bizUserApi
.userOrgTreeSelector({
.orgTreeSelector({
parentId: treeNode.dataRef.id
})
.then((res) => {

View File

@@ -187,4 +187,14 @@ public interface SaBaseLoginUserApi {
* @date 2026/2/12
*/
void refreshUserDataScope(String userId, List<SaBaseLoginUser.DataScope> dataScopeList);
/**
* 刷新在线用户的权限缓存Session权限变更后调用确保实时生效。
* 如果用户不在线则跳过。
*
* @param userId 用户ID
* @author xuyuxiang
* @date 2026/3/12
*/
void refreshOnlineUserPermission(String userId);
}

View File

@@ -223,4 +223,9 @@ public class ClientLoginUserApiProvider implements SaBaseLoginUserApi {
public void refreshUserDataScope(String userId, List<SaBaseLoginUser.DataScope> dataScopeList) {
// C端用户无数据范围无需刷新预计算表
}
@Override
public void refreshOnlineUserPermission(String userId) {
// C端用户暂无数据权限机制无需刷新
}
}

View File

@@ -58,6 +58,7 @@ import vip.xiaonuo.sys.modular.role.mapper.SysRoleMapper;
import vip.xiaonuo.sys.modular.role.param.*;
import vip.xiaonuo.sys.modular.role.result.*;
import vip.xiaonuo.sys.modular.role.service.SysRoleService;
import vip.xiaonuo.auth.api.SaBaseLoginUserApi;
import vip.xiaonuo.sys.modular.user.entity.SysUser;
import vip.xiaonuo.sys.modular.user.enums.SysUserStatusEnum;
import vip.xiaonuo.sys.modular.user.service.SysUserService;
@@ -95,6 +96,9 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
@Resource
private CommonCacheOperator commonCacheOperator;
@Resource(name = "loginUserApi")
private SaBaseLoginUserApi loginUserApi;
@Override
public Page<SysRole> page(SysRolePageParam sysRolePageParam) {
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<SysRole>().checkSqlInjection();
@@ -313,6 +317,10 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
.map(JSONUtil::toJsonStr).collect(Collectors.toList());
sysRelationService.saveRelationBatchWithClear(id, apiUrlList, SysRelationCategoryEnum.SYS_ROLE_HAS_PERMISSION.getValue(),
extJsonList);
// 刷新拥有该角色的所有在线用户的权限缓存
List<String> userIdList = sysRelationService.getRelationObjectIdListByTargetIdAndCategory(
id, SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue());
userIdList.forEach(loginUserApi::refreshOnlineUserPermission);
}
@Override
@@ -325,7 +333,11 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
public void grantUser(SysRoleGrantUserParam sysRoleGrantUserParam) {
String id = sysRoleGrantUserParam.getId();
List<String> grantInfoList = sysRoleGrantUserParam.getGrantInfoList();
// 记录变更前拥有该角色的用户(用于后续刷新被移除用户的权限)
Set<String> affectedUserIds = new HashSet<>();
if(sysRoleGrantUserParam.getRemoveFirst()) {
affectedUserIds.addAll(sysRelationService.getRelationObjectIdListByTargetIdAndCategory(
id, SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue()));
sysRelationService.remove(new LambdaQueryWrapper<SysRelation>().eq(SysRelation::getTargetId, id)
.eq(SysRelation::getCategory, SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue()));
}
@@ -336,6 +348,9 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
sysRelation.setCategory(SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue());
return sysRelation;
}).collect(Collectors.toList()));
// 合并新增用户,刷新所有受影响用户的权限缓存
affectedUserIds.addAll(grantInfoList);
affectedUserIds.forEach(loginUserApi::refreshOnlineUserPermission);
}
@Override

View File

@@ -12,10 +12,16 @@
*/
package vip.xiaonuo.sys.modular.user.provider;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import vip.xiaonuo.auth.api.SaBaseLoginUserApi;
import vip.xiaonuo.auth.core.pojo.SaBaseClientLoginUser;
@@ -34,6 +40,7 @@ import java.util.stream.Collectors;
* @author xuyuxiang
* @date 2022/4/29 13:36
**/
@Slf4j
@Service("loginUserApi")
public class SysLoginUserApiProvider implements SaBaseLoginUserApi {
@@ -216,4 +223,50 @@ public class SysLoginUserApiProvider implements SaBaseLoginUserApi {
public void refreshUserDataScope(String userId, List<SaBaseLoginUser.DataScope> dataScopeList) {
sysUserDataScopeService.refreshByUserId(userId, dataScopeList);
}
@Override
public void refreshOnlineUserPermission(String userId) {
// 获取该用户所有在线token
List<String> tokenList = StpUtil.getTokenValueListByLoginId(userId);
if (ObjectUtil.isEmpty(tokenList)) {
return;
}
// 获取用户基本信息
SaBaseLoginUser saBaseLoginUser = this.getUserById(userId);
if (ObjectUtil.isEmpty(saBaseLoginUser)) {
return;
}
// 获取角色列表
List<JSONObject> roleList = this.getRoleListByUserId(userId);
List<String> roleIdList = roleList.stream().map(j -> j.getStr("id")).collect(Collectors.toList());
List<String> roleCodeList = roleList.stream().map(j -> j.getStr("code")).collect(Collectors.toList());
List<String> userAndRoleIdList = CollectionUtil.unionAll(roleIdList, CollectionUtil.newArrayList(userId));
// 重新计算权限数据
List<String> buttonCodeList = this.getButtonCodeListListByUserAndRoleIdList(userAndRoleIdList);
List<String> mobileButtonCodeList = this.getMobileButtonCodeListListByUserIdAndRoleIdList(userAndRoleIdList);
List<SaBaseLoginUser.DataScope> dataScopeList = Convert.toList(SaBaseLoginUser.DataScope.class,
this.getPermissionListByUserIdAndRoleIdList(userAndRoleIdList, saBaseLoginUser.getOrgId()));
List<String> permissionCodeList = dataScopeList.stream()
.map(SaBaseLoginUser.DataScope::getApiUrl).collect(Collectors.toList());
// 填充到用户对象
saBaseLoginUser.setButtonCodeList(buttonCodeList);
saBaseLoginUser.setMobileButtonCodeList(mobileButtonCodeList);
saBaseLoginUser.setDataScopeList(dataScopeList);
saBaseLoginUser.setPermissionCodeList(permissionCodeList);
saBaseLoginUser.setRoleCodeList(roleCodeList);
// 写入该用户的所有TokenSession
for (String token : tokenList) {
try {
SaSession session = StpUtil.getTokenSessionByToken(token);
if (session != null) {
session.set("loginUser", saBaseLoginUser);
}
} catch (Exception e) {
log.warn(">>> 刷新用户权限缓存时跳过无效tokenuserId{}token{}", userId, token);
}
}
// 刷新预计算表
this.refreshUserDataScope(userId, dataScopeList);
log.info(">>> 已刷新在线用户权限缓存userId{}token数{}", userId, tokenList.size());
}
}

View File

@@ -65,6 +65,7 @@ import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.auth.api.SaBaseLoginUserApi;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.cache.CommonCacheOperator;
import vip.xiaonuo.common.enums.CommonGenderEnum;
@@ -260,6 +261,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@Resource
private SysUserPasswordService sysUserPasswordService;
@Resource(name = "loginUserApi")
private SaBaseLoginUserApi loginUserApi;
@Override
public SysLoginUser getUserById(String id) {
SysUser sysUser = this.getById(id);
@@ -1340,6 +1344,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
public void grantRole(SysUserGrantRoleParam sysUserGrantRoleParam) {
sysRelationService.saveRelationBatchWithClear(sysUserGrantRoleParam.getId(), sysUserGrantRoleParam.getRoleIdList(),
SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue());
// 刷新该用户的权限缓存
loginUserApi.refreshOnlineUserPermission(sysUserGrantRoleParam.getId());
}
@Override
@@ -1378,6 +1384,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
List<String> extJsonList = sysUserGrantResourceParam.getGrantInfoList().stream()
.map(JSONUtil::toJsonStr).collect(Collectors.toList());
sysRelationService.saveRelationBatchWithClear(sysUserGrantResourceParam.getId(), menuIdList, SysRelationCategoryEnum.SYS_USER_HAS_RESOURCE.getValue(), extJsonList);
// 刷新该用户的权限缓存
loginUserApi.refreshOnlineUserPermission(sysUserGrantResourceParam.getId());
}
@Override
@@ -1399,6 +1407,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
.map(JSONUtil::toJsonStr).collect(Collectors.toList());
sysRelationService.saveRelationBatchWithClear(id, apiUrlList, SysRelationCategoryEnum.SYS_USER_HAS_PERMISSION.getValue(),
extJsonList);
// 刷新该用户的权限缓存
loginUserApi.refreshOnlineUserPermission(id);
}
@Override