Commit a0a26c3d64fe25465b7367a6f8b5c43c1013d6d8

Authored by YunaiV
1 parent 643cc4cf

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

yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
... ... @@ -179,7 +179,7 @@ public class GlobalExceptionHandler {
179 179 if(ex.getCause() instanceof InvalidFormatException) {
180 180 InvalidFormatException invalidFormatException = (InvalidFormatException) ex.getCause();
181 181 return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", invalidFormatException.getValue()));
182   - }else {
  182 + } else {
183 183 return defaultExceptionHandler(ServletUtils.getRequest(), ex);
184 184 }
185 185 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
... ... @@ -10,6 +10,7 @@ import jakarta.annotation.security.PermitAll;
10 10 import org.springframework.context.annotation.Primary;
11 11 import org.springframework.validation.annotation.Validated;
12 12 import org.springframework.web.bind.annotation.PostMapping;
  13 +import org.springframework.web.bind.annotation.RequestBody;
13 14 import org.springframework.web.bind.annotation.RestController;
14 15  
15 16 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -30,7 +31,7 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi {
30 31 @Override
31 32 @PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth")
32 33 @PermitAll
33   - public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) {
  34 + public CommonResult<Boolean> authDevice(@RequestBody IotDeviceAuthReqDTO authReqDTO) {
34 35 return success(deviceService.authDevice(authReqDTO));
35 36 }
36 37  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
... ... @@ -235,6 +235,6 @@ public interface IotDeviceService {
235 235 * @param authReqDTO 认证信息
236 236 * @return 是否认证成功
237 237 */
238   - boolean authDevice(IotDeviceAuthReqDTO authReqDTO);
  238 + boolean authDevice(@Valid IotDeviceAuthReqDTO authReqDTO);
239 239  
240 240 }
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java
... ... @@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.http.router;
2 2  
3 3 import cn.hutool.core.lang.Assert;
4 4 import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.BooleanUtil;
5 6 import cn.hutool.core.util.StrUtil;
6 7 import cn.hutool.extra.spring.SpringUtil;
7 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
8 9 import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
9 10 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
  11 +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
10 12 import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
11 13 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
12 14 import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol;
... ... @@ -47,7 +49,7 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
47 49  
48 50 @Override
49 51 public CommonResult<Object> handle0(RoutingContext context) {
50   - // 解析参数
  52 + // 1. 解析参数
51 53 JsonObject body = context.body().asJsonObject();
52 54 String clientId = body.getString("clientId");
53 55 if (StrUtil.isEmpty(clientId)) {
... ... @@ -62,20 +64,23 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
62 64 throw invalidParamException("password 不能为空");
63 65 }
64 66  
65   - // 执行认证
  67 + // 2.1 执行认证
66 68 CommonResult<Boolean> result = deviceClientService.authDevice(new IotDeviceAuthReqDTO()
67 69 .setClientId(clientId).setUsername(username).setPassword(password));
68   - if (result == null || !result.isSuccess()) {
  70 + result.checkError();;
  71 + if (!BooleanUtil.isTrue(result.getData())) {
69 72 throw exception(DEVICE_AUTH_FAIL);
70 73 }
71   -
72   - // 生成 Token
  74 + // 2.2 生成 Token
73 75 IotDeviceAuthUtils.DeviceInfo deviceInfo = deviceTokenService.parseUsername(username);
74 76 Assert.notNull(deviceInfo, "设备信息不能为空");
75 77 String token = deviceTokenService.createToken(deviceInfo.getProductKey(), deviceInfo.getDeviceName());
76 78 Assert.notBlank(token, "生成 token 不能为空位");
77 79  
78   - // TODO @芋艿:发送上线消息;
  80 + // 3. 执行上线
  81 + deviceMessageProducer.sendDeviceMessage(IotDeviceMessage.of(deviceInfo.getProductKey(), deviceInfo.getDeviceName(),
  82 + protocol.getServerId())
  83 + .ofStateOnline());
79 84  
80 85 // 构建响应数据
81 86 return success(MapUtil.of("token", token));
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/IotDeviceClientServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.gateway.service.device;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
5 6 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
... ... @@ -31,7 +32,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi {
31 32 public void init() {
32 33 IotGatewayProperties.RpcProperties rpc = gatewayProperties.getRpc();
33 34 restTemplate = new RestTemplateBuilder()
34   - .rootUri(rpc.getUrl() + "/rpc-api/iot/device/")
  35 + .rootUri(rpc.getUrl() + "/rpc-api/iot/device")
35 36 .readTimeout(rpc.getReadTimeout())
36 37 .connectTimeout(rpc.getConnectTimeout())
37 38 .build();
... ... @@ -39,7 +40,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi {
39 40  
40 41 @Override
41 42 public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) {
42   - return doPost("auth", authReqDTO);
  43 + return doPost("/auth", authReqDTO);
43 44 }
44 45  
45 46 @SuppressWarnings("unchecked")
... ... @@ -48,6 +49,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi {
48 49 CommonResult<Boolean> result = restTemplate.postForObject(url, requestBody,
49 50 (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class);
50 51 log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result);
  52 + Assert.notNull(result, "请求结果不能为空");
51 53 return result;
52 54 } catch (Exception e) {
53 55 log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e);
... ...