feat(mobile): 增强人脸数据访问控制并优化订单查询逻辑

- 在删除人脸数据前增加用户权限校验,确保操作安全
- 移除订单详情接口中的用户身份强制绑定,简化查询流程
- 更新视频与图片资源查询方法,去除冗余的用户ID参数
- 调整Mapper层SQL语句,解耦人脸关联数据对用户的依赖
- 优化服务层代码结构,提升数据获取效率与一致性
This commit is contained in:
2025-11-17 10:06:32 +08:00
parent 9d708ae20c
commit d408c47963
7 changed files with 30 additions and 38 deletions

View File

@@ -1,13 +1,16 @@
package com.ycwl.basic.controller.mobile; package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.model.jwt.JwtInfo; import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp; import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
import com.ycwl.basic.model.mobile.face.FaceStatusResp; import com.ycwl.basic.model.mobile.face.FaceStatusResp;
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO; import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
import com.ycwl.basic.model.mobile.face.FaceRecognitionUpdateReq; import com.ycwl.basic.model.mobile.face.FaceRecognitionUpdateReq;
import com.ycwl.basic.model.mobile.face.FaceRecognitionDetailVO; import com.ycwl.basic.model.mobile.face.FaceRecognitionDetailVO;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO; import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity; import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.service.pc.FaceService; import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil; import com.ycwl.basic.utils.JwtTokenUtil;
@@ -28,6 +31,8 @@ public class AppFaceController {
@Autowired @Autowired
private FaceService faceService; private FaceService faceService;
@Autowired
private FaceRepository faceRepository;
/** /**
* 1、上传人脸照片 * 1、上传人脸照片
@@ -65,6 +70,18 @@ public class AppFaceController {
@DeleteMapping("/{faceId}") @DeleteMapping("/{faceId}")
public ApiResponse<String> deleteFace(@PathVariable("faceId") Long faceId) { public ApiResponse<String> deleteFace(@PathVariable("faceId") Long faceId) {
// 添加权限检查:验证当前用户是否拥有该 face
JwtInfo worker = JwtTokenUtil.getWorker();
Long userId = worker.getUserId();
FaceEntity face = faceRepository.getFace(faceId);
if (face == null) {
throw new BaseException("人脸数据不存在");
}
if (!face.getMemberId().equals(userId)) {
throw new BaseException("无权删除此人脸");
}
return faceService.deleteFace(faceId); return faceService.deleteFace(faceId);
} }

View File

@@ -262,36 +262,21 @@ public class AppOrderV2Controller {
} }
/** /**
* 用户查询自己的订单详情 * 查询订单详情
*/ */
@GetMapping("/detail/{orderId}") @GetMapping("/detail/{orderId}")
public ApiResponse<OrderV2DetailResponse> getUserOrderDetail(@PathVariable("orderId") Long orderId) { public ApiResponse<OrderV2DetailResponse> getUserOrderDetail(@PathVariable("orderId") Long orderId) {
String currentUserIdStr = BaseContextHandler.getUserId(); log.info("查询订单详情: orderId={}", orderId);
if (currentUserIdStr == null) {
log.warn("用户未登录");
return ApiResponse.fail("用户未登录");
}
Long currentUserId = Long.valueOf(currentUserIdStr);
log.info("用户查询订单详情: userId={}, orderId={}", currentUserId, orderId);
try { try {
OrderV2DetailResponse detail = orderService.getOrderDetail(orderId); OrderV2DetailResponse detail = orderService.getOrderDetail(orderId);
if (detail == null) { if (detail == null) {
return ApiResponse.fail("订单不存在"); return ApiResponse.fail("订单不存在");
} }
// 验证订单是否属于当前用户
if (!currentUserId.equals(detail.getMemberId())) {
log.warn("用户尝试访问他人订单: userId={}, orderId={}, orderOwner={}",
currentUserId, orderId, detail.getMemberId());
return ApiResponse.fail("无权访问该订单");
}
return ApiResponse.success(detail); return ApiResponse.success(detail);
} catch (Exception e) { } catch (Exception e) {
log.error("查询用户订单详情失败: userId={}, orderId={}", currentUserId, orderId, e); log.error("查询订单详情失败: orderId={}", orderId, e);
return ApiResponse.fail("查询失败:" + e.getMessage()); return ApiResponse.fail("查询失败:" + e.getMessage());
} }
} }

View File

@@ -72,9 +72,9 @@ public interface SourceMapper {
int hasRelationTo(Long memberId, Long sourceId, int type); int hasRelationTo(Long memberId, Long sourceId, int type);
List<SourceEntity> listVideoByScenicFaceRelation(Long scenicId, Long faceId); List<SourceEntity> listVideoByScenicFaceRelation(Long scenicId, Long faceId);
List<SourceEntity> listVideoByFaceRelation(Long memberId, Long faceId); List<SourceEntity> listVideoByFaceRelation(Long faceId);
List<SourceEntity> listImageByFaceRelation(Long memberId, Long faceId); List<SourceEntity> listImageByFaceRelation(Long faceId);
List<MemberSourceEntity> listByFaceRelation(Long faceId, Integer type); List<MemberSourceEntity> listByFaceRelation(Long faceId, Integer type);
SourceEntity getEntity(Long id); SourceEntity getEntity(Long id);

View File

@@ -125,7 +125,6 @@ public class GoodsServiceImpl implements GoodsService {
videoReqQuery.setScenicId(scenicId); videoReqQuery.setScenicId(scenicId);
videoReqQuery.setIsBuy(query.getIsBuy()); videoReqQuery.setIsBuy(query.getIsBuy());
videoReqQuery.setFaceId(query.getFaceId()); videoReqQuery.setFaceId(query.getFaceId());
videoReqQuery.setMemberId(Long.valueOf(BaseContextHandler.getUserId()));
//查询成片vlog //查询成片vlog
List<VideoRespVO> videoList = videoMapper.queryByRelation(videoReqQuery); List<VideoRespVO> videoList = videoMapper.queryByRelation(videoReqQuery);
videoList.forEach(videoRespVO -> { videoList.forEach(videoRespVO -> {
@@ -150,7 +149,6 @@ public class GoodsServiceImpl implements GoodsService {
sourceReqQuery.setScenicId(scenicId); sourceReqQuery.setScenicId(scenicId);
sourceReqQuery.setIsBuy(query.getIsBuy()); sourceReqQuery.setIsBuy(query.getIsBuy());
sourceReqQuery.setFaceId(query.getFaceId()); sourceReqQuery.setFaceId(query.getFaceId());
sourceReqQuery.setMemberId(Long.valueOf(BaseContextHandler.getUserId()));
//查询源素材 //查询源素材
List<SourceRespVO> sourceList = sourceMapper.queryByRelation(sourceReqQuery); List<SourceRespVO> sourceList = sourceMapper.queryByRelation(sourceReqQuery);
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId); ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
@@ -204,7 +202,6 @@ public class GoodsServiceImpl implements GoodsService {
SourceReqQuery sourceReqQuery = new SourceReqQuery(); SourceReqQuery sourceReqQuery = new SourceReqQuery();
sourceReqQuery.setScenicId(face.getScenicId()); sourceReqQuery.setScenicId(face.getScenicId());
sourceReqQuery.setIsBuy(query.getIsBuy()); sourceReqQuery.setIsBuy(query.getIsBuy());
sourceReqQuery.setMemberId(face.getMemberId());
sourceReqQuery.setType(sourceType); sourceReqQuery.setType(sourceType);
sourceReqQuery.setFaceId(face.getId()); sourceReqQuery.setFaceId(face.getId());
List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery); List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery);
@@ -563,7 +560,6 @@ public class GoodsServiceImpl implements GoodsService {
SourceReqQuery sourceReqQuery = new SourceReqQuery(); SourceReqQuery sourceReqQuery = new SourceReqQuery();
sourceReqQuery.setScenicId(face.getScenicId()); sourceReqQuery.setScenicId(face.getScenicId());
sourceReqQuery.setIsBuy(query.getIsBuy()); sourceReqQuery.setIsBuy(query.getIsBuy());
sourceReqQuery.setMemberId(face.getMemberId());
sourceReqQuery.setType(sourceType); sourceReqQuery.setType(sourceType);
sourceReqQuery.setFaceId(face.getId()); sourceReqQuery.setFaceId(face.getId());
List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery); List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery);
@@ -652,7 +648,6 @@ public class GoodsServiceImpl implements GoodsService {
Integer sourceType = query.getSourceType(); Integer sourceType = query.getSourceType();
SourceReqQuery sourceReqQuery = new SourceReqQuery(); SourceReqQuery sourceReqQuery = new SourceReqQuery();
sourceReqQuery.setScenicId(face.getScenicId()); sourceReqQuery.setScenicId(face.getScenicId());
sourceReqQuery.setMemberId(face.getMemberId());
sourceReqQuery.setType(sourceType); sourceReqQuery.setType(sourceType);
sourceReqQuery.setFaceId(query.getFaceId()); sourceReqQuery.setFaceId(query.getFaceId());
List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery); List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery);

View File

@@ -299,7 +299,7 @@ public class OrderServiceImpl implements OrderService {
List<Integer> _f = new ArrayList<>(); List<Integer> _f = new ArrayList<>();
orderItemList.forEach(item -> { orderItemList.forEach(item -> {
if (Integer.valueOf(1).equals(item.getGoodsType())) { // 原片 goodsId就是人脸ID if (Integer.valueOf(1).equals(item.getGoodsType())) { // 原片 goodsId就是人脸ID
List<SourceEntity> memberVideoEntityList = sourceMapper.listVideoByFaceRelation(order.getMemberId(), item.getGoodsId()); List<SourceEntity> memberVideoEntityList = sourceMapper.listVideoByFaceRelation(item.getGoodsId());
item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList())); item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList()));
if (!_f.contains(1)) { if (!_f.contains(1)) {
_f.add(1); _f.add(1);
@@ -320,7 +320,7 @@ public class OrderServiceImpl implements OrderService {
} }
} }
} else if (Integer.valueOf(2).equals(item.getGoodsType())) { // 照片 goodsId就是人脸ID } else if (Integer.valueOf(2).equals(item.getGoodsType())) { // 照片 goodsId就是人脸ID
List<SourceEntity> memberVideoEntityList = sourceMapper.listImageByFaceRelation(order.getMemberId(), item.getGoodsId()); List<SourceEntity> memberVideoEntityList = sourceMapper.listImageByFaceRelation(item.getGoodsId());
item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList())); item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList()));
if (!_f.contains(2)) { if (!_f.contains(2)) {
_f.add(2); _f.add(2);
@@ -519,14 +519,14 @@ public class OrderServiceImpl implements OrderService {
} }
orderItemList.forEach(item -> { orderItemList.forEach(item -> {
if (Integer.valueOf(1).equals(item.getGoodsType())) { // 原片 if (Integer.valueOf(1).equals(item.getGoodsType())) { // 原片
List<SourceEntity> memberVideoEntityList = sourceMapper.listVideoByFaceRelation(orderReqQuery.getMemberId(), item.getFaceId()); List<SourceEntity> memberVideoEntityList = sourceMapper.listVideoByFaceRelation(item.getFaceId());
item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList())); item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList()));
if (!memberVideoEntityList.isEmpty()) { if (!memberVideoEntityList.isEmpty()) {
item.setShootingTime(memberVideoEntityList.getFirst().getCreateTime()); item.setShootingTime(memberVideoEntityList.getFirst().getCreateTime());
item.setCount(1); item.setCount(1);
} }
} else if (Integer.valueOf(2).equals(item.getGoodsType())) { } else if (Integer.valueOf(2).equals(item.getGoodsType())) {
List<SourceEntity> memberVideoEntityList = sourceMapper.listImageByFaceRelation(orderReqQuery.getMemberId(), item.getFaceId()); List<SourceEntity> memberVideoEntityList = sourceMapper.listImageByFaceRelation(item.getFaceId());
item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList())); item.setCoverList(memberVideoEntityList.stream().map(SourceEntity::getUrl).collect(Collectors.toList()));
if (!memberVideoEntityList.isEmpty()) { if (!memberVideoEntityList.isEmpty()) {
item.setShootingTime(memberVideoEntityList.getFirst().getCreateTime()); item.setShootingTime(memberVideoEntityList.getFirst().getCreateTime());

View File

@@ -396,11 +396,6 @@
o.scenic_id o.scenic_id
from `order` AS o from `order` AS o
left join face f on o.face_id = f.id left join face f on o.face_id = f.id
<where>
<if test="memberId!=null">
and o.member_id=#{memberId}
</if>
</where>
order by o.create_at desc order by o.create_at desc
</select> </select>
<select id="appDetail" resultMap="AppBaseResultMap"> <select id="appDetail" resultMap="AppBaseResultMap">

View File

@@ -290,7 +290,7 @@
select s.*, ms.is_buy select s.*, ms.is_buy
from member_source ms from member_source ms
left join source s on ms.source_id = s.id left join source s on ms.source_id = s.id
where ms.face_id = #{faceId} and ms.member_id = #{memberId} and ms.type = 1 where ms.face_id = #{faceId} and ms.type = 1
order by create_time desc order by create_time desc
</select> </select>
<select id="listVideoByScenicFaceRelation" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity"> <select id="listVideoByScenicFaceRelation" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
@@ -304,7 +304,7 @@
select s.*, ms.is_buy select s.*, ms.is_buy
from member_source ms from member_source ms
left join source s on ms.source_id = s.id left join source s on ms.source_id = s.id
where ms.face_id = #{faceId} and ms.member_id = #{memberId} and ms.type = 2 where ms.face_id = #{faceId} and ms.type = 2
</select> </select>
<select id="getEntity" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity"> <select id="getEntity" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
select * select *