mirror of
https://gitee.com/xiaonuobase/snowy.git
synced 2026-03-22 02:37:16 +08:00
【更新】更新实时刷新数据权限范围及产品readme
This commit is contained in:
16
README.md
16
README.md
@@ -8,7 +8,8 @@
|
||||
|
||||
Snowy(SnowyAdmin)是国内首个国密前后端分离快速开发平台,集成国密加解密插件,
|
||||
软件层面完全符合等保测评要求,同时实现国产化机型、中间件、数据库适配,是您的不二之选!
|
||||
技术框架与密码结合,让更多的人认识密码,使用密码;更是让前后分离“密”不可分。
|
||||
将国密能力内置于技术框架底层,让密码技术从"专业门槛"变为"开箱即用",真正实现业务安全从底层做起。
|
||||
历经多年开源社区打磨与企业客户实践验证,新版本在大数据处理能力与安全体系方面实现了全面升级。
|
||||
|
||||
采用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源码头部的版权与作者声明及出处
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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端用户暂无数据权限机制,无需刷新
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(">>> 刷新用户权限缓存时跳过无效token,userId:{},token:{}", userId, token);
|
||||
}
|
||||
}
|
||||
// 刷新预计算表
|
||||
this.refreshUserDataScope(userId, dataScopeList);
|
||||
log.info(">>> 已刷新在线用户权限缓存,userId:{},token数:{}", userId, tokenList.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user