package cn.iocoder.yudao.module.iot.gateway.service.auth; import cn.hutool.core.lang.Assert; import cn.hutool.json.JSONObject; import cn.hutool.jwt.JWT; import cn.hutool.jwt.JWTUtil; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity; import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.gateway.enums.ErrorCodeConstants.DEVICE_TOKEN_EXPIRED; /** * IoT 设备 Token Service 实现类:调用远程的 device http 接口,进行设备 Token 生成、解析等逻辑 * * 注意:目前仅 HTTP 协议使用 * * @author 芋道源码 */ @Service @Slf4j public class IotDeviceTokenServiceImpl implements IotDeviceTokenService { @Resource private IotGatewayProperties gatewayProperties; @Override public String createToken(String productKey, String deviceName) { Assert.notBlank(productKey, "productKey 不能为空"); Assert.notBlank(deviceName, "deviceName 不能为空"); // 构建 JWT payload Map payload = new HashMap<>(); payload.put("productKey", productKey); payload.put("deviceName", deviceName); LocalDateTime expireTime = LocalDateTimeUtils.addTime(gatewayProperties.getToken().getExpiration()); payload.put("exp", LocalDateTimeUtils.toEpochSecond(expireTime)); // 过期时间(exp 是 JWT 规范推荐) // 生成 JWT Token return JWTUtil.createToken(payload, gatewayProperties.getToken().getSecret().getBytes()); } @Override public IotDeviceIdentity verifyToken(String token) { Assert.notBlank(token, "token 不能为空"); // 校验 JWT Token boolean verify = JWTUtil.verify(token, gatewayProperties.getToken().getSecret().getBytes()); if (!verify) { throw exception(DEVICE_TOKEN_EXPIRED); } // 解析 Token JWT jwt = JWTUtil.parseToken(token); JSONObject payload = jwt.getPayloads(); // 检查过期时间 Long exp = payload.getLong("exp"); if (exp == null || exp < System.currentTimeMillis() / 1000) { throw exception(DEVICE_TOKEN_EXPIRED); } String productKey = payload.getStr("productKey"); String deviceName = payload.getStr("deviceName"); Assert.notBlank(productKey, "productKey 不能为空"); Assert.notBlank(deviceName, "deviceName 不能为空"); return new IotDeviceIdentity(productKey, deviceName); } @Override public IotDeviceIdentity parseUsername(String username) { return IotDeviceAuthUtils.parseUsername(username); } }