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

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

View File

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

View File

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