package com.onekeycall.videotablet.controller; import com.google.gson.JsonObject; import com.onekeycall.videotablet.entity.DeviceInfo; import com.onekeycall.videotablet.entity.User; import com.onekeycall.videotablet.result.Result; import com.onekeycall.videotablet.service.DeviceSnService; import com.onekeycall.videotablet.service.UserService; import com.onekeycall.videotablet.utils.JwtUtil; import com.onekeycall.videotablet.utils.DevicePushUtils; import com.onekeycall.videotablet.utils.TextUtils; import org.apache.commons.lang3.RandomStringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.*; import java.util.*; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/sn") public class BindSnController { @Autowired private JwtUtil jwtUtil; @Autowired private UserService userService; @Autowired private DeviceSnService deviceSnService; @Autowired private RedisTemplate redisTemplate; Logger logger = LoggerFactory.getLogger(BindSnController.class); /** * 用户app发送绑定推送到手机 * * @param authHeader * @param deviceId * @param userId * @param sn * @return */ @PostMapping("/bind_sn") public Result bindSn( @RequestHeader("Authorization") String authHeader, @RequestHeader("Device-ID") String deviceId, @RequestParam(value = "user_id") String userId, @RequestParam(value = "sn") String sn) { logger.info("bindSn: authHeader={}, deviceId={}, userId={}, sn={}", authHeader, deviceId, userId, sn); if (!authHeader.startsWith("Bearer ")) { return Result.error().message("Invalid Authorization header"); } String token = authHeader.substring(7); // 去掉 "Bearer " 前缀 if (!jwtUtil.validateAccessToken(userId, token, deviceId)) { return Result.error().message("Invalid token"); } User user = userService.getUserByUserId(userId); String userPhone = user.getPhone(); DeviceInfo deviceInfo = deviceSnService.findBySn(sn); if (deviceInfo == null) { return Result.error().message("sn not found"); } if (!TextUtils.isEmpty(deviceInfo.getBindPhone())) { return Result.error().message("sn already bind"); } try { String verifyKey = RandomStringUtils.randomAlphanumeric(32); JsonObject params = new JsonObject(); params.addProperty("verify_key", verifyKey); params.addProperty("phone", userPhone); params.addProperty("expire_time", System.currentTimeMillis() + 60 * 1000); // PushUtils.aliyunAsyncPush("1", params.toString(), sn); DevicePushUtils.tpnsPush("1", params.toString(), sn); redisTemplate.opsForValue().set(sn, verifyKey, 1, TimeUnit.MINUTES); return Result.ok().message("send message success"); } catch (Exception e) { e.printStackTrace(); return Result.error().message(e.getMessage()); } } /** * 平板根据返回的数据绑定手机 * * @param deviceId * @param phone * @param sn * @param verifyKey * @return */ @PostMapping("/device_bind") public Result deviceBind( @RequestHeader("Device-ID") String deviceId, @RequestParam(value = "sn") String sn, @RequestParam(value = "phone") String phone, @RequestParam(value = "verify_key") String verifyKey) { User user = userService.getUserByPhone(phone); if (user == null) { return Result.notFound().message("user not found"); } String redisVerifyKey = (String) redisTemplate.opsForValue().get(sn); if (redisVerifyKey == null) { return Result.notFound().message("verify key not found"); } if (!Objects.equals(redisVerifyKey, verifyKey)) { return Result.error().message("verify key is not same"); } DeviceInfo oldDeviceInfo = deviceSnService.findBySn(sn); if (oldDeviceInfo == null) { return Result.notFound().message("sn not found"); } if (!TextUtils.isEmpty(oldDeviceInfo.getBindPhone())) { return Result.error().message("sn already bind"); } String userId = user.getUserId(); String deviceSig = jwtUtil.generateDeviceSig(sn); String deviceToken = jwtUtil.generateDeviceToken(sn, deviceId); oldDeviceInfo.setBindPhone(phone); oldDeviceInfo.setUserId(userId); oldDeviceInfo.setDeviceAlias(user.getNickname() + "的平板"); oldDeviceInfo.setBindTime(new Date()); oldDeviceInfo.setDeviceModel(deviceId); oldDeviceInfo.setBindSig(deviceSig); oldDeviceInfo.setToken(deviceToken); oldDeviceInfo.setSn(sn); deviceSnService.save(oldDeviceInfo); Map map = new LinkedHashMap<>(); map.put("phone", phone); map.put("device_token", deviceToken); map.put("device_sig", deviceSig); return Result.ok().data(map).message("bind success"); } /** * 获取平板sn绑定状态 * 标准的通过平板获取接口,需要 Device-Token Device-ID Device-Sig * @param deviceToken * @param deviceId * @param deviceSig * @param sn * @return */ // TODO: 2025/8/22 Device_Token在docker无法被接收到,使用Device-Token代替 @GetMapping("/get_bind_statu") public Result getBindStatus( @RequestHeader("Device-Token") String deviceToken, @RequestHeader("Device-ID") String deviceId, @RequestHeader("Device-Sig") String deviceSig, @RequestParam(value = "sn") String sn) { if (!jwtUtil.validateDeviceToken(deviceToken, deviceId, sn)) { return Result.error().message("Invalid token"); } DeviceInfo deviceInfo = deviceSnService.findBySn(sn); if (deviceInfo == null) { return Result.notFound().message("sn not found"); } if (!deviceInfo.getBindSig().equals(deviceSig)) { return Result.error().message("device sig not match"); } if (TextUtils.isEmpty(deviceInfo.getBindPhone())) { return Result.error().message("sn not bind"); } Map map = new LinkedHashMap<>(); map.put("bind_status", 1); map.put("device_alias", deviceInfo.getDeviceAlias()); map.put("bind_phone", deviceInfo.getBindPhone()); map.put("user_id", deviceInfo.getUserId()); map.put("add_time", deviceInfo.getAddTime()); map.put("bind_time", deviceInfo.getBindTime()); return Result.ok().data(map).message("sn bind"); } }