feat:【IoT 物联网】增加网关 HTTP 协议的鉴权,基于 JWT 轻量级(已测试)

This commit is contained in:
YunaiV 2025-06-03 22:27:04 +08:00
parent 643cc4cfd2
commit a0a26c3d64
5 changed files with 19 additions and 11 deletions

View File

@ -179,7 +179,7 @@ public class GlobalExceptionHandler {
if(ex.getCause() instanceof InvalidFormatException) {
InvalidFormatException invalidFormatException = (InvalidFormatException) ex.getCause();
return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", invalidFormatException.getValue()));
}else {
} else {
return defaultExceptionHandler(ServletUtils.getRequest(), ex);
}
}

View File

@ -10,6 +10,7 @@ import jakarta.annotation.security.PermitAll;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -30,7 +31,7 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi {
@Override
@PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth")
@PermitAll
public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) {
public CommonResult<Boolean> authDevice(@RequestBody IotDeviceAuthReqDTO authReqDTO) {
return success(deviceService.authDevice(authReqDTO));
}

View File

@ -235,6 +235,6 @@ public interface IotDeviceService {
* @param authReqDTO 认证信息
* @return 是否认证成功
*/
boolean authDevice(IotDeviceAuthReqDTO authReqDTO);
boolean authDevice(@Valid IotDeviceAuthReqDTO authReqDTO);
}

View File

@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.http.router;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol;
@ -47,7 +49,7 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
@Override
public CommonResult<Object> handle0(RoutingContext context) {
// 解析参数
// 1. 解析参数
JsonObject body = context.body().asJsonObject();
String clientId = body.getString("clientId");
if (StrUtil.isEmpty(clientId)) {
@ -62,20 +64,23 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
throw invalidParamException("password 不能为空");
}
// 执行认证
// 2.1 执行认证
CommonResult<Boolean> result = deviceClientService.authDevice(new IotDeviceAuthReqDTO()
.setClientId(clientId).setUsername(username).setPassword(password));
if (result == null || !result.isSuccess()) {
result.checkError();;
if (!BooleanUtil.isTrue(result.getData())) {
throw exception(DEVICE_AUTH_FAIL);
}
// 生成 Token
// 2.2 生成 Token
IotDeviceAuthUtils.DeviceInfo deviceInfo = deviceTokenService.parseUsername(username);
Assert.notNull(deviceInfo, "设备信息不能为空");
String token = deviceTokenService.createToken(deviceInfo.getProductKey(), deviceInfo.getDeviceName());
Assert.notBlank(token, "生成 token 不能为空位");
// TODO @芋艿发送上线消息
// 3. 执行上线
deviceMessageProducer.sendDeviceMessage(IotDeviceMessage.of(deviceInfo.getProductKey(), deviceInfo.getDeviceName(),
protocol.getServerId())
.ofStateOnline());
// 构建响应数据
return success(MapUtil.of("token", token));

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.gateway.service.device;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
@ -31,7 +32,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi {
public void init() {
IotGatewayProperties.RpcProperties rpc = gatewayProperties.getRpc();
restTemplate = new RestTemplateBuilder()
.rootUri(rpc.getUrl() + "/rpc-api/iot/device/")
.rootUri(rpc.getUrl() + "/rpc-api/iot/device")
.readTimeout(rpc.getReadTimeout())
.connectTimeout(rpc.getConnectTimeout())
.build();
@ -39,7 +40,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi {
@Override
public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) {
return doPost("auth", authReqDTO);
return doPost("/auth", authReqDTO);
}
@SuppressWarnings("unchecked")
@ -48,6 +49,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi {
CommonResult<Boolean> result = restTemplate.postForObject(url, requestBody,
(Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class);
log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result);
Assert.notNull(result, "请求结果不能为空");
return result;
} catch (Exception e) {
log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e);