数据联动列表:数据权限隔离
This commit is contained in:
parent
f8a8474f0f
commit
5d8ae0e2f0
@ -73,11 +73,11 @@ public class NotifyTemplateServiceImpl implements INotifyTemplateService {
|
||||
// notifyTemplate.setTenantId(user.getUserId());
|
||||
// }
|
||||
// 查询所属机构
|
||||
if (null != user.getDeptId()) {
|
||||
notifyTemplate.setTenantId(user.getDept().getDeptUserId());
|
||||
} else {
|
||||
notifyTemplate.setTenantId(user.getUserId());
|
||||
}
|
||||
// if (null != user.getDeptId()) {
|
||||
// notifyTemplate.setTenantId(user.getDept().getDeptUserId());
|
||||
// } else {
|
||||
// notifyTemplate.setTenantId(user.getUserId());
|
||||
// }
|
||||
List<NotifyTemplate> notifyTemplates = notifyTemplateMapper.selectNotifyTemplateList(notifyTemplate);
|
||||
if (org.apache.commons.collections4.CollectionUtils.isEmpty(notifyTemplates)) {
|
||||
return notifyTemplates;
|
||||
|
||||
@ -42,12 +42,16 @@ public class ThingsModelPushController extends BaseController {
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/** 获取详情 */
|
||||
/** 获取详情(超管看全部,机构/终端用户只能看自己机构的) */
|
||||
@ApiOperation("获取推送配置详情")
|
||||
@PreAuthorize("@ss.hasPermi('iot:push:query')")
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getById(@PathVariable Long id) {
|
||||
return AjaxResult.success(pushConfigService.selectById(id));
|
||||
ThingsModelPushConfig config = pushConfigService.selectById(id);
|
||||
if (config == null) {
|
||||
return AjaxResult.error("推送配置不存在或无访问权限");
|
||||
}
|
||||
return AjaxResult.success(config);
|
||||
}
|
||||
|
||||
/** 新增 */
|
||||
@ -66,6 +70,7 @@ public class ThingsModelPushController extends BaseController {
|
||||
@Log(title = "推送配置", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody ThingsModelPushConfig config) {
|
||||
pushConfigService.assertOwned(config.getId());
|
||||
return toAjax(pushConfigService.updateConfig(config));
|
||||
}
|
||||
|
||||
@ -75,6 +80,7 @@ public class ThingsModelPushController extends BaseController {
|
||||
@Log(title = "推送配置状态", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/status")
|
||||
public AjaxResult changeStatus(@RequestBody ThingsModelPushConfig config) {
|
||||
pushConfigService.assertOwned(config.getId());
|
||||
return toAjax(pushConfigService.updateStatus(config.getId(), config.getStatus()));
|
||||
}
|
||||
|
||||
@ -84,6 +90,12 @@ public class ThingsModelPushController extends BaseController {
|
||||
@Log(title = "推送配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
if (ids == null || ids.length == 0) {
|
||||
return AjaxResult.error("请选择要删除的推送配置");
|
||||
}
|
||||
for (Long id : ids) {
|
||||
pushConfigService.assertOwned(id);
|
||||
}
|
||||
return toAjax(pushConfigService.deleteByIds(ids));
|
||||
}
|
||||
|
||||
@ -97,7 +109,7 @@ public class ThingsModelPushController extends BaseController {
|
||||
public AjaxResult manualPush(@PathVariable Long id) {
|
||||
ThingsModelPushConfig config = pushConfigService.selectById(id);
|
||||
if (config == null) {
|
||||
return AjaxResult.error("推送配置不存在");
|
||||
return AjaxResult.error("推送配置不存在或无访问权限");
|
||||
}
|
||||
if (config.getStatus() == null || config.getStatus() == 0) {
|
||||
return AjaxResult.error("推送配置已停用,请先启用");
|
||||
|
||||
@ -71,7 +71,7 @@ public class ThingsModelPushConfig extends BaseEntity {
|
||||
@ApiModelProperty("租户名称")
|
||||
private String tenantName;
|
||||
|
||||
@ApiModelProperty("配置归属用户ID(列表按此过滤;与接收用户 userIds 不同)")
|
||||
@ApiModelProperty("创建人用户ID(数据隔离按 tenantId 过滤,与此字段及接收用户 userIds 均不同)")
|
||||
private Long userId;
|
||||
|
||||
/** 物模型项列表(非持久化,前端用) */
|
||||
|
||||
@ -29,6 +29,14 @@ public interface DeviceMapper extends BaseMapperX<Device> {
|
||||
*/
|
||||
public Device selectDeviceByDeviceId(Long deviceId);
|
||||
|
||||
/**
|
||||
* 只查设备的归属(tenant_id / tenant_name),用于按设备推导数据归属
|
||||
*
|
||||
* @param deviceId 设备主键
|
||||
* @return 设备归属,设备不存在时返回 null
|
||||
*/
|
||||
Device selectTenantByDeviceId(Long deviceId);
|
||||
|
||||
/**
|
||||
* 查询设备和产品总数
|
||||
*
|
||||
|
||||
@ -19,6 +19,9 @@ public interface ThingsModelPushConfigMapper {
|
||||
|
||||
ThingsModelPushConfig selectById(Long id);
|
||||
|
||||
/** 只查归属租户ID,用于越权校验(避免加载物模型项和接收用户) */
|
||||
Long selectTenantIdById(Long id);
|
||||
|
||||
List<ThingsModelPushConfig> selectList(ThingsModelPushConfig query);
|
||||
|
||||
/** 查询所有启用的推送配置(含物模型项和接收用户) */
|
||||
|
||||
@ -21,6 +21,11 @@ public interface IThingsModelPushConfigService {
|
||||
/** 按产品/设备查询启用配置 */
|
||||
List<ThingsModelPushConfig> selectEnabledByProductAndDevice(Long productId, Long deviceId);
|
||||
|
||||
/**
|
||||
* 校验配置在当前登录账号的数据范围内,越权抛异常
|
||||
*/
|
||||
void assertOwned(Long configId);
|
||||
|
||||
int insertConfig(ThingsModelPushConfig config);
|
||||
|
||||
int updateConfig(ThingsModelPushConfig config);
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
package com.fastbee.iot.service.impl;
|
||||
|
||||
import com.fastbee.common.core.domain.entity.SysDept;
|
||||
import com.fastbee.common.core.domain.entity.SysUser;
|
||||
import com.fastbee.common.core.domain.model.LoginUser;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.DateUtils;
|
||||
import com.fastbee.common.utils.SecurityUtils;
|
||||
import com.fastbee.common.utils.StringUtils;
|
||||
import com.fastbee.iot.domain.Device;
|
||||
import com.fastbee.iot.domain.PushModelItem;
|
||||
import com.fastbee.iot.domain.PushUser;
|
||||
import com.fastbee.iot.domain.ThingsModelPushConfig;
|
||||
import com.fastbee.iot.mapper.DeviceMapper;
|
||||
import com.fastbee.iot.mapper.ThingsModelPushConfigMapper;
|
||||
import com.fastbee.iot.service.IThingsModelPushConfigService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -16,6 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -29,18 +36,31 @@ public class ThingsModelPushConfigServiceImpl implements IThingsModelPushConfigS
|
||||
|
||||
@Resource
|
||||
private ThingsModelPushConfigMapper mapper;
|
||||
@Resource
|
||||
private DeviceMapper deviceMapper;
|
||||
|
||||
@Override
|
||||
public ThingsModelPushConfig selectById(Long id) {
|
||||
return mapper.selectById(id);
|
||||
ThingsModelPushConfig config = mapper.selectById(id);
|
||||
if (config == null) {
|
||||
return null;
|
||||
}
|
||||
assertInScope(config.getTenantId());
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThingsModelPushConfig> selectList(ThingsModelPushConfig query) {
|
||||
query.setUserId(SecurityUtils.getUserId());
|
||||
// 归属条件只由服务端计算,忽略前端传入值:超管看全部,机构/终端用户只看自己
|
||||
query.setTenantId(resolveScopeTenantId());
|
||||
return mapper.selectList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertOwned(Long configId) {
|
||||
assertInScope(mapper.selectTenantIdById(configId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThingsModelPushConfig> selectAllEnabled() {
|
||||
return mapper.selectAllEnabled();
|
||||
@ -55,6 +75,11 @@ public class ThingsModelPushConfigServiceImpl implements IThingsModelPushConfigS
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int insertConfig(ThingsModelPushConfig config) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Device deviceTenant = loadDeviceTenant(config.getDeviceId());
|
||||
Long ownerTenantId = resolveOwnerTenantId(loginUser, deviceTenant);
|
||||
config.setTenantId(ownerTenantId);
|
||||
// 名称必须与最终归属ID同源,否则会写出 tenant_id=3 / tenant_name=admin 这类错配数据
|
||||
config.setTenantName(resolveOwnerTenantName(loginUser, deviceTenant, ownerTenantId));
|
||||
config.setUserId(loginUser.getUserId());
|
||||
config.setCreateBy(loginUser.getUsername());
|
||||
config.setCreateTime(DateUtils.getNowDate());
|
||||
@ -110,6 +135,77 @@ public class ThingsModelPushConfigServiceImpl implements IThingsModelPushConfigS
|
||||
mapper.updateLastPushTime(id, new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前登录账号的查询范围:超级管理员返回 null(不限),其余账号返回其归属租户ID
|
||||
*/
|
||||
private Long resolveScopeTenantId() {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (SecurityUtils.isAdmin(loginUser.getUserId())) {
|
||||
return null;
|
||||
}
|
||||
return resolveAccountTenantId(loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据归属租户:<b>优先取所挂设备的归属</b>,设备无归属时回落登录账号的机构。
|
||||
* 推送配置的主体是设备而非创建人——超管替下级机构建配置时必须落到该机构,否则机构看不到自己的配置。
|
||||
*/
|
||||
private Long resolveOwnerTenantId(LoginUser loginUser, Device deviceTenant) {
|
||||
if (deviceTenant != null && deviceTenant.getTenantId() != null) {
|
||||
return deviceTenant.getTenantId();
|
||||
}
|
||||
return resolveAccountTenantId(loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 归属名称,必须与 {@link #resolveOwnerTenantId} 的结果同源:
|
||||
* 归属ID取自设备时名称就用设备的(哪怕为空,如实反映),否则回落登录账号。
|
||||
*/
|
||||
private String resolveOwnerTenantName(LoginUser loginUser, Device deviceTenant, Long ownerTenantId) {
|
||||
if (deviceTenant != null && Objects.equals(deviceTenant.getTenantId(), ownerTenantId)) {
|
||||
return deviceTenant.getTenantName();
|
||||
}
|
||||
return resolveAccountTenantName(loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录账号自身归属:机构用户取机构绑定的系统账号ID,终端用户(无机构)取自身账号ID
|
||||
*/
|
||||
private Long resolveAccountTenantId(LoginUser loginUser) {
|
||||
SysUser user = loginUser.getUser();
|
||||
SysDept dept = user.getDept();
|
||||
if (user.getDeptId() != null && dept != null && dept.getDeptUserId() != null) {
|
||||
return dept.getDeptUserId();
|
||||
}
|
||||
return loginUser.getUserId();
|
||||
}
|
||||
|
||||
private String resolveAccountTenantName(LoginUser loginUser) {
|
||||
SysUser user = loginUser.getUser();
|
||||
SysDept dept = user.getDept();
|
||||
if (user.getDeptId() != null && dept != null && dept.getDeptUserId() != null
|
||||
&& StringUtils.isNotEmpty(dept.getDeptUserName())) {
|
||||
return dept.getDeptUserName();
|
||||
}
|
||||
return user.getUserName();
|
||||
}
|
||||
|
||||
/** 设备归属,deviceId 为空或 0(未指定/全设备)时返回 null */
|
||||
private Device loadDeviceTenant(Long deviceId) {
|
||||
if (deviceId == null || deviceId == 0L) {
|
||||
return null;
|
||||
}
|
||||
return deviceMapper.selectTenantByDeviceId(deviceId);
|
||||
}
|
||||
|
||||
private void assertInScope(Long tenantId) {
|
||||
Long scopeTenantId = resolveScopeTenantId();
|
||||
if (scopeTenantId == null || scopeTenantId.equals(tenantId)) {
|
||||
return;
|
||||
}
|
||||
throw new ServiceException("推送配置不存在或无访问权限");
|
||||
}
|
||||
|
||||
private void saveItemsAndUsers(ThingsModelPushConfig config) {
|
||||
if (CollectionUtils.isNotEmpty(config.getItems())) {
|
||||
List<PushModelItem> items = config.getItems();
|
||||
|
||||
@ -550,6 +550,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
where device_id = #{deviceId}
|
||||
</select>
|
||||
|
||||
<resultMap type="com.fastbee.iot.domain.Device" id="DeviceTenantResult">
|
||||
<result property="tenantId" column="tenant_id" />
|
||||
<result property="tenantName" column="tenant_name" />
|
||||
</resultMap>
|
||||
|
||||
<select id="selectTenantByDeviceId" parameterType="Long" resultMap="DeviceTenantResult">
|
||||
select d.tenant_id, d.tenant_name from iot_device d
|
||||
where d.device_id = #{deviceId}
|
||||
</select>
|
||||
|
||||
<select id="selectDeviceInfoBySerialNumber" parameterType="String" resultMap="DeviceImeiIccidTypeResult">
|
||||
select
|
||||
p.device_type as device_type,
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
<result property="status" column="status"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="tenantName" column="tenant_name"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
@ -53,9 +54,10 @@
|
||||
<sql id="baseColumns">
|
||||
c.id, c.config_name, c.product_id, c.device_id, c.serial_number,
|
||||
c.template_id, c.push_interval, c.last_push_time, c.status,
|
||||
c.tenant_id, c.tenant_name, c.create_by, c.create_time,
|
||||
c.tenant_id, c.tenant_name, c.user_id, c.create_by, c.create_time,
|
||||
c.update_by, c.update_time,p.product_name, p.device_type,
|
||||
d.device_name,d.network_address AS device_address, nt.name AS template_name
|
||||
d.device_name,
|
||||
d.network_address AS device_address, nt.name AS template_name
|
||||
</sql>
|
||||
|
||||
<sql id="baseJoins">
|
||||
@ -74,6 +76,16 @@
|
||||
AND c.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectTenantIdById" resultType="java.lang.Long">
|
||||
SELECT
|
||||
c.tenant_id
|
||||
FROM
|
||||
iot_things_model_push_config c
|
||||
WHERE
|
||||
c.id = #{id}
|
||||
AND c.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectList" resultMap="ConfigResult">
|
||||
SELECT
|
||||
<include refid="baseColumns"/>
|
||||
@ -131,6 +143,7 @@
|
||||
status,
|
||||
tenant_id,
|
||||
tenant_name,
|
||||
user_id,
|
||||
create_by,
|
||||
create_time,
|
||||
del_flag
|
||||
@ -146,6 +159,7 @@
|
||||
#{status},
|
||||
#{tenantId},
|
||||
#{tenantName},
|
||||
#{userId},
|
||||
#{createBy},
|
||||
#{createTime},
|
||||
'0'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user