Commit a0a26c3d64fe25465b7367a6f8b5c43c1013d6d8
1 parent
643cc4cf
feat:【IoT 物联网】增加网关 HTTP 协议的鉴权,基于 JWT 轻量级(已测试)
Showing
5 changed files
with
19 additions
and
11 deletions
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,7 +179,7 @@ public class GlobalExceptionHandler { | ||
| 179 | if(ex.getCause() instanceof InvalidFormatException) { | 179 | if(ex.getCause() instanceof InvalidFormatException) { |
| 180 | InvalidFormatException invalidFormatException = (InvalidFormatException) ex.getCause(); | 180 | InvalidFormatException invalidFormatException = (InvalidFormatException) ex.getCause(); |
| 181 | return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", invalidFormatException.getValue())); | 181 | return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", invalidFormatException.getValue())); |
| 182 | - }else { | 182 | + } else { |
| 183 | return defaultExceptionHandler(ServletUtils.getRequest(), ex); | 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,6 +10,7 @@ import jakarta.annotation.security.PermitAll; | ||
| 10 | import org.springframework.context.annotation.Primary; | 10 | import org.springframework.context.annotation.Primary; |
| 11 | import org.springframework.validation.annotation.Validated; | 11 | import org.springframework.validation.annotation.Validated; |
| 12 | import org.springframework.web.bind.annotation.PostMapping; | 12 | import org.springframework.web.bind.annotation.PostMapping; |
| 13 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 13 | import org.springframework.web.bind.annotation.RestController; | 14 | import org.springframework.web.bind.annotation.RestController; |
| 14 | 15 | ||
| 15 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 16 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| @@ -30,7 +31,7 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi { | @@ -30,7 +31,7 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi { | ||
| 30 | @Override | 31 | @Override |
| 31 | @PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth") | 32 | @PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth") |
| 32 | @PermitAll | 33 | @PermitAll |
| 33 | - public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) { | 34 | + public CommonResult<Boolean> authDevice(@RequestBody IotDeviceAuthReqDTO authReqDTO) { |
| 34 | return success(deviceService.authDevice(authReqDTO)); | 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,6 +235,6 @@ public interface IotDeviceService { | ||
| 235 | * @param authReqDTO 认证信息 | 235 | * @param authReqDTO 认证信息 |
| 236 | * @return 是否认证成功 | 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,11 +2,13 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.http.router; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | import cn.hutool.core.map.MapUtil; | 4 | import cn.hutool.core.map.MapUtil; |
| 5 | +import cn.hutool.core.util.BooleanUtil; | ||
| 5 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 6 | import cn.hutool.extra.spring.SpringUtil; | 7 | import cn.hutool.extra.spring.SpringUtil; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 8 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 8 | import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; | 9 | import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; |
| 9 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; | 10 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; |
| 11 | +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 10 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | 12 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 11 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; | 13 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; |
| 12 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; | 14 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; |
| @@ -47,7 +49,7 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler { | @@ -47,7 +49,7 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler { | ||
| 47 | 49 | ||
| 48 | @Override | 50 | @Override |
| 49 | public CommonResult<Object> handle0(RoutingContext context) { | 51 | public CommonResult<Object> handle0(RoutingContext context) { |
| 50 | - // 解析参数 | 52 | + // 1. 解析参数 |
| 51 | JsonObject body = context.body().asJsonObject(); | 53 | JsonObject body = context.body().asJsonObject(); |
| 52 | String clientId = body.getString("clientId"); | 54 | String clientId = body.getString("clientId"); |
| 53 | if (StrUtil.isEmpty(clientId)) { | 55 | if (StrUtil.isEmpty(clientId)) { |
| @@ -62,20 +64,23 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler { | @@ -62,20 +64,23 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler { | ||
| 62 | throw invalidParamException("password 不能为空"); | 64 | throw invalidParamException("password 不能为空"); |
| 63 | } | 65 | } |
| 64 | 66 | ||
| 65 | - // 执行认证 | 67 | + // 2.1 执行认证 |
| 66 | CommonResult<Boolean> result = deviceClientService.authDevice(new IotDeviceAuthReqDTO() | 68 | CommonResult<Boolean> result = deviceClientService.authDevice(new IotDeviceAuthReqDTO() |
| 67 | .setClientId(clientId).setUsername(username).setPassword(password)); | 69 | .setClientId(clientId).setUsername(username).setPassword(password)); |
| 68 | - if (result == null || !result.isSuccess()) { | 70 | + result.checkError();; |
| 71 | + if (!BooleanUtil.isTrue(result.getData())) { | ||
| 69 | throw exception(DEVICE_AUTH_FAIL); | 72 | throw exception(DEVICE_AUTH_FAIL); |
| 70 | } | 73 | } |
| 71 | - | ||
| 72 | - // 生成 Token | 74 | + // 2.2 生成 Token |
| 73 | IotDeviceAuthUtils.DeviceInfo deviceInfo = deviceTokenService.parseUsername(username); | 75 | IotDeviceAuthUtils.DeviceInfo deviceInfo = deviceTokenService.parseUsername(username); |
| 74 | Assert.notNull(deviceInfo, "设备信息不能为空"); | 76 | Assert.notNull(deviceInfo, "设备信息不能为空"); |
| 75 | String token = deviceTokenService.createToken(deviceInfo.getProductKey(), deviceInfo.getDeviceName()); | 77 | String token = deviceTokenService.createToken(deviceInfo.getProductKey(), deviceInfo.getDeviceName()); |
| 76 | Assert.notBlank(token, "生成 token 不能为空位"); | 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 | return success(MapUtil.of("token", token)); | 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 | package cn.iocoder.yudao.module.iot.gateway.service.device; | 1 | package cn.iocoder.yudao.module.iot.gateway.service.device; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; | 5 | import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; |
| 5 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; | 6 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; |
| @@ -31,7 +32,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi { | @@ -31,7 +32,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi { | ||
| 31 | public void init() { | 32 | public void init() { |
| 32 | IotGatewayProperties.RpcProperties rpc = gatewayProperties.getRpc(); | 33 | IotGatewayProperties.RpcProperties rpc = gatewayProperties.getRpc(); |
| 33 | restTemplate = new RestTemplateBuilder() | 34 | restTemplate = new RestTemplateBuilder() |
| 34 | - .rootUri(rpc.getUrl() + "/rpc-api/iot/device/") | 35 | + .rootUri(rpc.getUrl() + "/rpc-api/iot/device") |
| 35 | .readTimeout(rpc.getReadTimeout()) | 36 | .readTimeout(rpc.getReadTimeout()) |
| 36 | .connectTimeout(rpc.getConnectTimeout()) | 37 | .connectTimeout(rpc.getConnectTimeout()) |
| 37 | .build(); | 38 | .build(); |
| @@ -39,7 +40,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi { | @@ -39,7 +40,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi { | ||
| 39 | 40 | ||
| 40 | @Override | 41 | @Override |
| 41 | public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) { | 42 | public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) { |
| 42 | - return doPost("auth", authReqDTO); | 43 | + return doPost("/auth", authReqDTO); |
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | @SuppressWarnings("unchecked") | 46 | @SuppressWarnings("unchecked") |
| @@ -48,6 +49,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi { | @@ -48,6 +49,7 @@ public class IotDeviceClientServiceImpl implements IotDeviceCommonApi { | ||
| 48 | CommonResult<Boolean> result = restTemplate.postForObject(url, requestBody, | 49 | CommonResult<Boolean> result = restTemplate.postForObject(url, requestBody, |
| 49 | (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class); | 50 | (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class); |
| 50 | log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result); | 51 | log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result); |
| 52 | + Assert.notNull(result, "请求结果不能为空"); | ||
| 51 | return result; | 53 | return result; |
| 52 | } catch (Exception e) { | 54 | } catch (Exception e) { |
| 53 | log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e); | 55 | log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e); |