绑定后返回token和签名

This commit is contained in:
2025-08-22 09:21:12 +08:00
parent f0cffe3e12
commit 6b5eeee6ee
3 changed files with 40 additions and 42 deletions

View File

@@ -13,18 +13,20 @@ import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.util.Base64; import java.util.*;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@RestController @RestController
@@ -41,6 +43,9 @@ public class BindSnController {
@Autowired @Autowired
private RedisTemplate<String, Object> redisTemplate; private RedisTemplate<String, Object> redisTemplate;
Logger logger = LoggerFactory.getLogger(BindSnController.class);
/** /**
* 用户app发送绑定推送到手机 * 用户app发送绑定推送到手机
* *
@@ -54,6 +59,8 @@ public class BindSnController {
public Result bindSn( public Result bindSn(
@RequestHeader("Authorization") String authHeader, @RequestHeader("Device-ID") String deviceId, @RequestHeader("Authorization") String authHeader, @RequestHeader("Device-ID") String deviceId,
@RequestParam(value = "user_id") String userId, @RequestParam(value = "sn") String sn) { @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 ")) { if (!authHeader.startsWith("Bearer ")) {
return Result.error().message("Invalid Authorization header"); return Result.error().message("Invalid Authorization header");
} }
@@ -92,19 +99,24 @@ public class BindSnController {
/** /**
* 平板根据返回的数据绑定手机 * 平板根据返回的数据绑定手机
* *
* @param authHeader
* @param deviceId * @param deviceId
* @param userId * @param phone
* @param sn * @param sn
* @param verifyKey * @param verifyKey
* @return * @return
*/ */
@PostMapping("/device_bind") @PostMapping("/device_bind")
public Result deviceBind( public Result deviceBind(
@RequestHeader("Authorization") String authHeader, @RequestHeader("Device-ID") String deviceId, @RequestHeader("Device-ID") String deviceId,
@RequestParam(value = "user_id") String userId, @RequestParam(value = "sn") String sn, @RequestParam(value = "sn") String sn, @RequestParam(value = "phone") String phone,
@RequestParam(value = "verify_key") String verifyKey) { @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); String redisVerifyKey = (String) redisTemplate.opsForValue().get(sn);
if (redisVerifyKey == null) { if (redisVerifyKey == null) {
return Result.notFound().message("verify key not found"); return Result.notFound().message("verify key not found");
@@ -113,21 +125,6 @@ public class BindSnController {
return Result.error().message("verify key is not same"); return Result.error().message("verify key is not same");
} }
if (!authHeader.startsWith("Bearer ")) {
return Result.unAuthorized().message("Invalid Authorization header");
}
String token = authHeader.substring(7); // 去掉 "Bearer " 前缀
if (!jwtUtil.validateAccessToken(userId, token, deviceId)) {
return Result.unAuthorized().message("Invalid token");
}
User user = userService.getUserByUserId(userId);
if (user == null) {
return Result.notFound().message("user not found");
}
String userPhone = user.getPhone();
DeviceInfo oldDeviceInfo = deviceSnService.findBySn(sn); DeviceInfo oldDeviceInfo = deviceSnService.findBySn(sn);
if (oldDeviceInfo == null) { if (oldDeviceInfo == null) {
return Result.notFound().message("sn not found"); return Result.notFound().message("sn not found");
@@ -137,10 +134,12 @@ public class BindSnController {
return Result.error().message("sn already bind"); return Result.error().message("sn already bind");
} }
String userId = user.getUserId();
String deviceSig = jwtUtil.generateDeviceSig(sn); String deviceSig = jwtUtil.generateDeviceSig(sn);
String deviceToken = jwtUtil.generateDeviceToken(sn, deviceId); String deviceToken = jwtUtil.generateDeviceToken(sn, deviceId);
oldDeviceInfo.setBindPhone(userPhone); oldDeviceInfo.setBindPhone(phone);
oldDeviceInfo.setUserId(userId);
oldDeviceInfo.setDeviceAlias(user.getNickname() + "的平板"); oldDeviceInfo.setDeviceAlias(user.getNickname() + "的平板");
oldDeviceInfo.setBindTime(new Date()); oldDeviceInfo.setBindTime(new Date());
oldDeviceInfo.setDeviceModel(deviceId); oldDeviceInfo.setDeviceModel(deviceId);
@@ -148,30 +147,28 @@ public class BindSnController {
oldDeviceInfo.setToken(deviceToken); oldDeviceInfo.setToken(deviceToken);
oldDeviceInfo.setSn(sn); oldDeviceInfo.setSn(sn);
deviceSnService.save(oldDeviceInfo); deviceSnService.save(oldDeviceInfo);
Map<String, Object> map = new HashMap<>();
try { map.put("phone", phone);
PushUtils.aliyunAsyncPush(verifyKey, userPhone, sn); map.put("device_token", deviceToken);
return Result.ok().message("bind success"); map.put("device_sig", deviceSig);
} catch (Exception e) { return Result.ok().data(map).message("bind success");
e.printStackTrace();
return Result.error().message(e.getMessage());
}
} }
/** /**
* 获取平板sn绑定状态 * 获取平板sn绑定状态
* *
* @param Device_Token * @param deviceToken
* @param deviceId * @param deviceId
* @param Device_Sig * @param deviceSig
* @param sn * @param sn
* @return * @return
*/ */
@GetMapping("/get_bind_statu") // TODO: 2025/8/22 Device_Token在docker无法被接收到使用Device-Token代替
@PostMapping("/get_bind_statu")
public Result getBindStatus( public Result getBindStatus(
@RequestHeader("Device_Token") String Device_Token, @RequestHeader("Device-ID") String deviceId, @RequestHeader("Device-Token") String deviceToken, @RequestHeader("Device-ID") String deviceId,
@RequestHeader("Device_Sig") String Device_Sig, @RequestParam(value = "sn") String sn) { @RequestHeader("Device-Sig") String deviceSig,
@RequestParam(value = "sn") String sn) {
DeviceInfo deviceInfo = deviceSnService.findBySn(sn); DeviceInfo deviceInfo = deviceSnService.findBySn(sn);
if (deviceInfo == null) { if (deviceInfo == null) {
@@ -185,5 +182,4 @@ public class BindSnController {
return Result.ok().message("sn bind"); return Result.ok().message("sn bind");
} }
} }

View File

@@ -1,6 +1,8 @@
package com.onekeycall.videotablet.handler; package com.onekeycall.videotablet.handler;
import com.onekeycall.videotablet.result.Result; import com.onekeycall.videotablet.result.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
@@ -12,9 +14,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.resource.NoResourceFoundException; import org.springframework.web.servlet.resource.NoResourceFoundException;
import reactor.core.publisher.Mono;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -27,6 +27,7 @@ import java.util.Map;
*/ */
@ControllerAdvice @ControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
// 替换为 WebFlux 的异常处理 // 替换为 WebFlux 的异常处理
// @ExceptionHandler(ResponseStatusException.class) // @ExceptionHandler(ResponseStatusException.class)

View File

@@ -18,6 +18,7 @@ import org.glassfish.jaxb.core.v2.TODO;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@@ -118,7 +119,7 @@ public class PushUtils {
JsonObject params = new JsonObject(); JsonObject params = new JsonObject();
params.addProperty("verify_key", verifyKey); params.addProperty("verify_key", verifyKey);
params.addProperty("phone", phone); params.addProperty("phone", phone);
params.addProperty("time", System.currentTimeMillis()); params.addProperty("expire_time", System.currentTimeMillis() + 60 * 1000);
Message message = new Message(); Message message = new Message();
// 推送标题 // 推送标题