完成阿里token获取

This commit is contained in:
wulin 2023-10-24 10:36:45 +08:00
parent 942e911f02
commit 8c3c71309c
27 changed files with 223 additions and 46 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -0,0 +1,26 @@
package com.qiuguo.iot.base.constans;
public class HttpHeaderConstans {
public static String API_TYPE = "api-type";
public static String API_TOKEN = "api-token";
public static String BOX_SIGNATURE = "signature";
public static String FIRMWARE_VERSION = "firmwareVersion";
public static String DEVICT_TYPE = "deviceType";
public static String OS_VERSION = "osVersion";
public static String OS = "os";
public static String USER_ID = "userId";
public static String BOX_BIND = "isBind";
public static String BOX_SN = "sn";
public static String TIME = "time";
}

View File

@ -29,4 +29,8 @@ public class RedisConstans {
public static String USER_BOX_INFO = "user_box_info:";
public static String TY_QUEUE_LIST = "ty_queue_list:"; //通义千问的前缀
/**
* 阿里语音合成token
*/
public static String ALI_TTS_TOKEN = "ali_tts_token";
}

View File

@ -2,6 +2,8 @@ package com.qiuguo.iot.data.service.device;
import com.alibaba.fastjson.JSONObject;
import com.qiuguo.iot.base.constans.RedisConstans;
import com.qiuguo.iot.base.enums.YesNo;
import com.qiuguo.iot.base.utils.StringUtils;
import com.qiuguo.iot.data.entity.device.DeviceInfoEntity;
@ -17,6 +19,7 @@ import org.hswebframework.web.crud.service.GenericReactiveCrudService;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.Arrays;
import java.util.Date;

BIN
iot-modules/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -3,17 +3,10 @@ spring:
nacos:
discovery:
# 服务注册地址
<<<<<<< HEAD
server-addr: 8.139.5.211:30731
config:
# 配置中心地址
server-addr: 8.139.5.211:30731
=======
server-addr: qiuguo-nacos.qiuguo-cloud:8848
config:
# 配置中心地址
server-addr: qiuguo-nacos.qiuguo-cloud:8848
>>>>>>> 64da585a2f5a786febdbeaafd130d2fd086ee8e1
# 配置文件格式
file-extension: yml
# 共享配置

Binary file not shown.

View File

@ -88,6 +88,19 @@
<version>3.1.8</version>
</dependency>
<dependency>
<groupId>com.alibaba.nls</groupId>
<artifactId>nls-sdk-common</artifactId>
<version>2.2.10</version>
</dependency>
<!-- for token -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.6.4</version>
</dependency>
</dependencies>
<build>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,17 +1,35 @@
package com.qiuguo.iot.box.websocket.api.controller;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nls.client.AccessToken;
import com.qiuguo.iot.base.constans.HttpHeaderConstans;
import com.qiuguo.iot.base.constans.RedisConstans;
import com.qiuguo.iot.base.enums.AskTypeEnum;
import com.qiuguo.iot.base.utils.StringUtils;
import com.qiuguo.iot.box.websocket.api.domain.box.BoxSession;
import com.qiuguo.iot.box.websocket.api.service.WebsocketService;
import com.qiuguo.iot.data.entity.device.DeviceInfoEntity;
import com.qiuguo.iot.data.request.device.DeviceInfoRequest;
import com.qiuguo.iot.data.service.device.DeviceInfoService;
import com.qiuguo.iot.data.service.system.SystemTalkAnswerConfigService;
import com.qiuguo.iot.third.nlp.Nlp;
import com.qiuguo.iot.third.service.LacNlpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.time.Duration;
@RestController
@Slf4j
@RequestMapping("/websocket")
@ -25,6 +43,25 @@ public class WebsocketController {
@Autowired
SystemTalkAnswerConfigService systemTalkAnswerConfigService;
@Autowired
private ReactiveStringRedisTemplate reactiveStringRedisTemplate;
@Resource
private DeviceInfoService deviceInfoService;
@Value("${device.checkTimeout}")
private Boolean checkTimeout;
@Value("${device.timeout}")
private Long timeOut;//2分钟
@Value("${Ali.accesskeId}")
private String aliAccessKeyId;
@Value("${Ali.accesskeySecret}")
private String aliAccessSecret;
@GetMapping("/push/message")
public Mono<String> pushMessage(@RequestParam String message, @RequestParam String id, @RequestParam Integer type) {
@ -43,4 +80,92 @@ public class WebsocketController {
return lacNlpService.geSingletNlp(value);
}
private Mono<DeviceInfoEntity> getDeviceInfo(String sn){
DeviceInfoRequest request = new DeviceInfoRequest();
request.setSn(sn);
return deviceInfoService.selectDeviceInfoByRequest(request).defaultIfEmpty(new DeviceInfoEntity()).map(dv -> {
if(dv.getId() != null){
String redis = JSONObject.toJSONString(dv);
reactiveStringRedisTemplate.opsForValue().set(RedisConstans.DEVICE_INFO + dv.getSn(), redis, Duration.ofHours(1)).subscribe();//直接提交订阅
}
return dv;
});
}
@GetMapping("/tts/token")
public Mono<String> getTtsToken(ServerHttpRequest serverHttpRequest) {
serverHttpRequest.getHeaders();
Long linkTime = Long.valueOf(serverHttpRequest.getHeaders().get(HttpHeaderConstans.TIME).get(0));
String sn = serverHttpRequest.getHeaders().get(HttpHeaderConstans.BOX_SN).get(0);
String signature = serverHttpRequest.getHeaders().get(HttpHeaderConstans.BOX_SIGNATURE).get(0);
if(checkTimeout && System.currentTimeMillis() - linkTime > timeOut){
//关闭连接
log.info("设备{},请求数据已超时", sn);
return Mono.just("请求超时");
}
return reactiveStringRedisTemplate.opsForValue()
.get(RedisConstans.DEVICE_INFO + sn).defaultIfEmpty("")
.flatMap(s -> {
if(com.qiuguo.iot.base.utils.StringUtils.isNotBlank(s)){
try{
DeviceInfoEntity dv = JSONObject.parseObject(s, DeviceInfoEntity.class);
if(dv.getId() == null){
log.info("redis设备缓存异常清楚");
return getDeviceInfo(sn);
}
return Mono.just(dv);
}catch (Exception e){
log.info("转换异常清除redis。下次连接成功{}", e);
}
}
return getDeviceInfo(sn);
}).flatMap(dv ->{
String snMd5 = MD5.create().digestHex(sn).toUpperCase();
String wifiMd5 = MD5.create().digestHex(dv.getWifiMac()).toUpperCase();
String btMd5 = MD5.create().digestHex(dv.getBtMac()).toUpperCase();
String signalMd5 = MD5.create().digestHex(snMd5 + wifiMd5 + btMd5 + linkTime + dv.getKey()).toUpperCase();
if(!signalMd5.equals(signature)){
log.info("设备{},验签失败。正常签:{}", sn, signalMd5);
return Mono.just("验签失败");
}else{
log.info("设备{},验签成功", sn);
return reactiveStringRedisTemplate.opsForValue()
.get(RedisConstans.ALI_TTS_TOKEN).defaultIfEmpty("")
.flatMap(toen -> {
if(StringUtils.isNotBlank(toen)){
return Mono.just(toen);
}
try {
AccessToken accessToken = new AccessToken(aliAccessKeyId, aliAccessSecret);
accessToken.apply();
String token = accessToken.getToken();
long expireTime = accessToken.getExpireTime() - 600000L;//提前10分钟更新
//return Mono.just(token);
return reactiveStringRedisTemplate.opsForValue().set(RedisConstans.ALI_TTS_TOKEN,
token, Duration.ofMillis(expireTime)).flatMap(t -> {
return Mono.just(token);
});
}catch (Exception e){
log.info("获取阿里Token异常{}", e);
}
return Mono.just("获取token异常");
});
}
});
}
}

View File

@ -10,4 +10,8 @@ public class BoxSession extends BaseSession {
* TTS合成声音的声音标识
*/
String ttsId;
/**
* 阿里token
*/
String aliToken;
}

View File

@ -0,0 +1,13 @@
package com.qiuguo.iot.box.websocket.api.domain.user;
import com.qiuguo.iot.box.websocket.api.domain.BaseSession;
import com.qiuguo.iot.data.resp.third.MusicResp;
import lombok.Data;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.FluxSink;
@Data
public class UserSession extends BaseSession {
}

View File

@ -11,6 +11,7 @@ import com.qiuguo.iot.box.websocket.api.domain.box.resp.ActionResp;
import com.qiuguo.iot.box.websocket.api.domain.box.resp.BoxMessageResp;
import com.qiuguo.iot.box.websocket.api.domain.box.resp.DateTimeResp;
import com.qiuguo.iot.box.websocket.api.domain.box.resp.WeatherResp;
import com.qiuguo.iot.box.websocket.api.domain.user.UserSession;
import com.qiuguo.iot.data.constants.YunxiRabbitConst;
import com.qiuguo.iot.data.entity.device.DeviceUserBindEntity;
import com.qiuguo.iot.data.entity.device.DeviceUserTalkRecordEntity;
@ -106,12 +107,11 @@ public class BaseWebSocketProcess {
protected SystemTalkBindU3dService systemTalkBindU3dService;
protected static ConcurrentHashMap<Long, BaseSession> userGroup = new ConcurrentHashMap<>();
protected static ConcurrentHashMap<Long, UserSession> userGroup = new ConcurrentHashMap<>();
protected static ConcurrentHashMap<String, BoxSession> boxGroup = new ConcurrentHashMap<>();
protected static String apiType = "api-type";
protected static String apiToken = "api-token";
private String getSendStr(StringBuilder sb, String message){
String old = sb.toString() + message;
@ -194,7 +194,7 @@ public class BaseWebSocketProcess {
return Mono.empty();
});
}
})/*.subscribeOn(Schedulers.boundedElastic()).subscribe()*/;
});
}
private Mono<Integer> saveTalkRecord(BaseSession baseSession, Action action, String text){
@ -333,8 +333,9 @@ public class BaseWebSocketProcess {
}
return weatherService.tianqiApi(req).flatMap(t ->{
if(t.getData() == null){
return sendMessage(action, baseSession, "该城市不支持天气查询", action.getSystemTalkAnswerConfigEntity().getAnswerType());
//return Mono.empty();
return sendMessage(action, baseSession,
"该城市不支持天气查询",
action.getSystemTalkAnswerConfigEntity().getAnswerType());
}
TianqiapiItemResp item = null;
@ -856,7 +857,7 @@ public class BaseWebSocketProcess {
return null;
}
public BaseSession getUserSessionWithUserId(Long userId) {
public UserSession getUserSessionWithUserId(Long userId) {
if(userGroup.containsKey(userId)){
return userGroup.get(userId);
}

View File

@ -3,6 +3,7 @@ package com.qiuguo.iot.box.websocket.api.handler;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSONObject;
import com.qiuguo.iot.base.annotation.WebSocketMapping;
import com.qiuguo.iot.base.constans.HttpHeaderConstans;
import com.qiuguo.iot.base.constans.RedisConstans;
import com.qiuguo.iot.base.enums.*;
import com.qiuguo.iot.base.model.UserDeviceInfoModel;
@ -31,6 +32,7 @@ import reactor.util.context.Context;
import javax.annotation.Resource;
import java.time.Duration;
@Component
@WebSocketMapping("/websocket/box")
@Slf4j
@ -51,14 +53,13 @@ public class BoxWebSocketHandler extends BaseWebSocketProcess implements WebSock
private NlpService nlpService;
@Override
public Mono<Void> handle(WebSocketSession session) {
// 在生产环境中需对url中的参数进行检验如token不符合要求的连接的直接关闭
HandshakeInfo handshakeInfo = session.getHandshakeInfo();
HttpHeaders headers = handshakeInfo.getHeaders();
String sn = headers.get("sn").get(0);
Long linkTime = Long.parseLong(headers.get("time").get(0));
String sn = headers.get(HttpHeaderConstans.BOX_SN).get(0);
Long linkTime = Long.parseLong(headers.get(HttpHeaderConstans.TIME).get(0));
if(checkTimeout && System.currentTimeMillis() - linkTime > timeOut){
//关闭连接
log.info("设备{},请求数据已超时", sn);
@ -72,9 +73,9 @@ public class BoxWebSocketHandler extends BaseWebSocketProcess implements WebSock
log.info("局域网IP替换成杭州ip115.205.2.137");
ip = "115.205.2.137";
}
String signature = headers.get("signature").get(0);
Long userId = Long.parseLong(headers.get("userId").get(0));
Integer isBind = Integer.parseInt(headers.get("isBind").get(0));
String signature = headers.get(HttpHeaderConstans.BOX_SIGNATURE).get(0);
Long userId = Long.parseLong(headers.get(HttpHeaderConstans.USER_ID).get(0));
Integer isBind = Integer.parseInt(headers.get(HttpHeaderConstans.BOX_BIND).get(0));
//
BoxSession boxSession = new BoxSession();
@ -268,6 +269,8 @@ public class BoxWebSocketHandler extends BaseWebSocketProcess implements WebSock
}else{
boxSession.setTtsId(entity.getTts());
if(entity.getIsBind().equals(YesNo.YES.getCode())){
//通知用户端设备绑定成功
sendNoticeToUser(userId, "设备联网成功,设备序列号:" + dv.getSn(), AskTypeEnum.BOX_ON_LINE.getCode());

View File

@ -2,13 +2,13 @@ package com.qiuguo.iot.box.websocket.api.handler;
import com.alibaba.fastjson.JSONObject;
import com.qiuguo.iot.base.annotation.WebSocketMapping;
import com.qiuguo.iot.base.constans.HttpHeaderConstans;
import com.qiuguo.iot.base.enums.AskTypeEnum;
import com.qiuguo.iot.base.enums.DeviceTypeEnum;
import com.qiuguo.iot.base.enums.ResponeEnum;
import com.qiuguo.iot.base.enums.YesNo;
import com.qiuguo.iot.base.utils.WebClientUtils;
import com.qiuguo.iot.box.websocket.api.domain.BaseSession;
import com.qiuguo.iot.box.websocket.api.domain.box.BoxSession;
import com.qiuguo.iot.box.websocket.api.domain.user.UserSession;
import com.qiuguo.iot.box.websocket.api.domain.user.UserTalkMessage;
import com.qiuguo.iot.box.websocket.api.filter.LogMdcConfiguration;
import com.qiuguo.iot.box.websocket.api.filter.LogWebFilter;
@ -58,17 +58,17 @@ public class CustomerWebSocketHandler extends BaseWebSocketProcess implements We
HandshakeInfo handshakeInfo = session.getHandshakeInfo();
HttpHeaders headers = handshakeInfo.getHeaders();
//List<String> tokens = headers.get("token");
String type = headers.get(apiType).get(0);
String token = headers.get(apiToken).get(0);
Long userId = Long.valueOf(headers.get("userId").get(0));
Long linkTime = Long.parseLong(headers.get("time").get(0));
String type = headers.get(HttpHeaderConstans.API_TYPE).get(0);
String token = headers.get(HttpHeaderConstans.API_TOKEN).get(0);
Long userId = Long.valueOf(headers.get(HttpHeaderConstans.USER_ID).get(0));
Long linkTime = Long.parseLong(headers.get(HttpHeaderConstans.TIME).get(0));
if(checkTimeout && System.currentTimeMillis() - linkTime > timeOut){
//关闭连接
log.info("用户{},请求数据已超时", userId);
return session.close();
}
String ip = headers.get(LogWebFilter.HEAD_IP).get(0);
BaseSession userSession = new BaseSession();
UserSession userSession = new UserSession();
userSession.setUserId(userId);
userSession.setSession(session);
userSession.setCustomerIP(ip);
@ -105,12 +105,12 @@ public class CustomerWebSocketHandler extends BaseWebSocketProcess implements We
}).then();
}
private Mono<Void> newMessage(WebSocketMessage webSocketMessage, BaseSession userSession){
private Mono<Void> newMessage(WebSocketMessage webSocketMessage, UserSession userSession){
MDC.put(LogMdcConfiguration.PRINT_LOG_ID, userSession.getLogId());
String text = webSocketMessage.getPayloadAsText();
log.info("收到用户消息:{}", text);
UserTalkMessage userTalkMessage = JSONObject.parseObject(text, UserTalkMessage.class);
BaseSession userSession1 = getUserSessionWithUserId(userTalkMessage.getUserId());
UserSession userSession1 = getUserSessionWithUserId(userTalkMessage.getUserId());
if(!userSession.equals(userSession1)){
log.info("消息发送异常或者未验签就收到信息不是同一个链接。可能传错用户ID");
return closeSendMsg(userSession, "请等待验签结束或者用户ID可能错误", AskTypeEnum.TTS.getCode()).flatMap(b -> {
@ -127,8 +127,8 @@ public class CustomerWebSocketHandler extends BaseWebSocketProcess implements We
}
private Mono<Void> disconnect(BaseSession userSession){
BaseSession userSession1 = getUserSessionWithUserId(userSession.getUserId());
private Mono<Void> disconnect(UserSession userSession){
UserSession userSession1 = getUserSessionWithUserId(userSession.getUserId());
if(userSession == userSession1){
userGroup.remove(userSession.getUserId());//断链后及时移除
log.info("用户断开连接userId{}", userSession.getUserId());
@ -136,10 +136,10 @@ public class CustomerWebSocketHandler extends BaseWebSocketProcess implements We
return Mono.empty();
}
private Mono<Void> checkToken(BaseSession userSession, String type, String token, Long userId){
private Mono<Void> checkToken(UserSession userSession, String type, String token, Long userId){
Map<String, String> reqHead = new HashMap<>();
reqHead.put(apiType, type);
reqHead.put(apiToken, token);
reqHead.put(HttpHeaderConstans.API_TYPE, type);
reqHead.put(HttpHeaderConstans.API_TOKEN, token);
return WebClientUtils.get(checkTokenUrl, reqHead).defaultIfEmpty(new JSONObject()).flatMap(jsonObject -> {
log.info("验签获取的数据{}", jsonObject);
if(jsonObject.getInteger("code").equals(ResponeEnum.SUCESS.getCode())){
@ -165,7 +165,7 @@ public class CustomerWebSocketHandler extends BaseWebSocketProcess implements We
}else{
normalSendMsg(userSession, "您暂未绑定果宝儿Box快去绑定吧", AskTypeEnum.TTS.getCode());
}
BaseSession oldUserSession = getUserSessionWithUserId(userId);
UserSession oldUserSession = getUserSessionWithUserId(userId);
userGroup.put(userId, userSession);
if(oldUserSession != null){
return closeSendMsg(oldUserSession, "您在其他地方登录", AskTypeEnum.TTS.getCode());

View File

@ -1,4 +0,0 @@
package com.qiuguo.iot.box.websocket.api.service;
public interface IActionService {
}

View File

@ -1,6 +0,0 @@
package com.qiuguo.iot.box.websocket.api.service.impl;
import com.qiuguo.iot.box.websocket.api.service.IActionService;
public class QianWenActionServiceImpl implements IActionService {
}

View File

@ -52,4 +52,6 @@ lac:
url: http://192.168.8.211:6000/qg_human/lac_word
Ali:
qianwen: 'sk-8d64677afaf6404cb83ce1910b5b2558'
qianwen: 'sk-8d64677afaf6404cb83ce1910b5b2558'
accesskeId: 'LTAI5t7d1iZb18SvGQhtDnyN'
accesskeySecret: 'j2Cp3uCDGuiA7xZIJmYOCmDhJl9HuJ'