diff --git a/fastbee-notify/fastbee-notify-web/src/main/java/com/fastbee/notify/service/impl/NotifyTemplateServiceImpl.java b/fastbee-notify/fastbee-notify-web/src/main/java/com/fastbee/notify/service/impl/NotifyTemplateServiceImpl.java index 74ea17fa..1de8ebfc 100644 --- a/fastbee-notify/fastbee-notify-web/src/main/java/com/fastbee/notify/service/impl/NotifyTemplateServiceImpl.java +++ b/fastbee-notify/fastbee-notify-web/src/main/java/com/fastbee/notify/service/impl/NotifyTemplateServiceImpl.java @@ -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 notifyTemplates = notifyTemplateMapper.selectNotifyTemplateList(notifyTemplate); if (org.apache.commons.collections4.CollectionUtils.isEmpty(notifyTemplates)) { return notifyTemplates; diff --git a/fastbee-open-api/src/main/java/com/fastbee/controller/push/ThingsModelPushController.java b/fastbee-open-api/src/main/java/com/fastbee/controller/push/ThingsModelPushController.java index 31672faa..a395ffc5 100644 --- a/fastbee-open-api/src/main/java/com/fastbee/controller/push/ThingsModelPushController.java +++ b/fastbee-open-api/src/main/java/com/fastbee/controller/push/ThingsModelPushController.java @@ -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("推送配置已停用,请先启用"); diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModelPushConfig.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModelPushConfig.java index 72f5bcb7..fbb8dac1 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModelPushConfig.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModelPushConfig.java @@ -71,7 +71,7 @@ public class ThingsModelPushConfig extends BaseEntity { @ApiModelProperty("租户名称") private String tenantName; - @ApiModelProperty("配置归属用户ID(列表按此过滤;与接收用户 userIds 不同)") + @ApiModelProperty("创建人用户ID(数据隔离按 tenantId 过滤,与此字段及接收用户 userIds 均不同)") private Long userId; /** 物模型项列表(非持久化,前端用) */ diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java index 59c7c707..63cf0178 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java @@ -29,6 +29,14 @@ public interface DeviceMapper extends BaseMapperX { */ public Device selectDeviceByDeviceId(Long deviceId); + /** + * 只查设备的归属(tenant_id / tenant_name),用于按设备推导数据归属 + * + * @param deviceId 设备主键 + * @return 设备归属,设备不存在时返回 null + */ + Device selectTenantByDeviceId(Long deviceId); + /** * 查询设备和产品总数 * diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ThingsModelPushConfigMapper.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ThingsModelPushConfigMapper.java index 049605de..29a2be5e 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ThingsModelPushConfigMapper.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ThingsModelPushConfigMapper.java @@ -19,6 +19,9 @@ public interface ThingsModelPushConfigMapper { ThingsModelPushConfig selectById(Long id); + /** 只查归属租户ID,用于越权校验(避免加载物模型项和接收用户) */ + Long selectTenantIdById(Long id); + List selectList(ThingsModelPushConfig query); /** 查询所有启用的推送配置(含物模型项和接收用户) */ diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IThingsModelPushConfigService.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IThingsModelPushConfigService.java index f9e81f54..ee1c883b 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IThingsModelPushConfigService.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IThingsModelPushConfigService.java @@ -21,6 +21,11 @@ public interface IThingsModelPushConfigService { /** 按产品/设备查询启用配置 */ List selectEnabledByProductAndDevice(Long productId, Long deviceId); + /** + * 校验配置在当前登录账号的数据范围内,越权抛异常 + */ + void assertOwned(Long configId); + int insertConfig(ThingsModelPushConfig config); int updateConfig(ThingsModelPushConfig config); diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelPushConfigServiceImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelPushConfigServiceImpl.java index e9f8fe68..15041108 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelPushConfigServiceImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelPushConfigServiceImpl.java @@ -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 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 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); + } + + /** + * 数据归属租户:优先取所挂设备的归属,设备无归属时回落登录账号的机构。 + * 推送配置的主体是设备而非创建人——超管替下级机构建配置时必须落到该机构,否则机构看不到自己的配置。 + */ + 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 items = config.getItems(); diff --git a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml index ce77b044..87b6aaa1 100644 --- a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml +++ b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml @@ -550,6 +550,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where device_id = #{deviceId} + + + + + + + + +