上一篇制作完CA之后如何接入平台

简介: 目的: 使用java代码利用自己制作的CA证书接入物联网平台1.上一篇文档https://developer.aliyun.com/article/782644?spm=a2c6h.13148508.0.0.630c4f0eZVwUkB有详细的证书制作过程2.如何上传以及绑定设备参考官网文档https://help.aliyun.com/document_detail/145689.html?spm=a2c4g.11186623.6.726.55935bb3utpBHD#title-kj4-8v0-g81都是控制台操作 ,不详细写了

注意点1 ,设备证书的 SN 码如何获取 ,也就是绑定设备需要的

也就是这个

image.png

方法

查看设备证书 SN openssl x509 -noout -text -in device-1.crt

就是这个 ,去掉中间的冒号

image.png



代码实现


pom.xml 配置

<dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.61</version></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.13</version></dependency>


证书准备


根证书root

物联网平台根证书,可以从官网文档中下载 https://help.aliyun.com/document_detail/73742.html

设备证书

image.png

设备私钥

image.png


代码实现


/*   
 * Copyright © 2019 Alibaba. All rights reserved.
 */
package com.aliyun.iot.demo;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import com.alibaba.fastjson.JSONObject;
/**
 * mqtt客户端直连阿里云物联网平台,基于eclipse paho开发 <br>
 * 基于X.509认证接入 https://help.aliyun.com/document_detail/140588.html
 */
public class IotMqttClientWithAuthByX509 {
    // ===================需要用户填写的参数开始===========================
    // 站点id,根据实际站点获取对应id,https://help.aliyun.com/document_detail/40654.html
    private static String regionId = "cn-shanghai"; // 目前只支持上海,也就是华东2节点
    // ===================需要用户填写的参数结束===========================
    // 设备证书
    private String certPath = "";
    // 设备私钥,无密码
    private String privateKeyPath = "";
    // 密码固定为空
    private String privateKeyPassword = "";
    // X.509认证返回信息的topic,无需创建,无需订阅,直接使用
    private static final String AUTH_TOPIC = "/ext/auth/identity/response";
    // 设备productKey,用于接受平台下发的productKey,无需填写
    private static String productKey = "";
    // 设备deviceName,用于接受平台下发的deviceName,无需填写
    private static String deviceName = "";
    // mqtt客户端
    private MqttClient sampleClient = null;
    /**
     * 建立mqtt连接
     * 
     * @param certPath 证书路径
     * @param privateKeyPath 私钥路径
     * @param privateKeyPassword 私钥密码,目前固定为空
     */
    public void connect(String certPath, String privateKeyPath, String privateKeyPassword) {
        this.certPath = certPath;
        this.privateKeyPath = privateKeyPath;
        this.privateKeyPassword = privateKeyPassword;
        // 接入域名
        String broker = "ssl://x509.itls." + regionId + ".aliyuncs.com:1883";
        // 表示客户端ID,建议使用设备的MAC地址或SN码,64字符内
        String clientId = ".";
        // 只能securemode=2表示使用TLS
        String clientOpts = "|securemode=2|";
        // mqtt接入客户端ID
        String mqttClientId = clientId + clientOpts;
        // 建立mqtt连接,使用证书认证,所以不需要username和password
        connect(broker, mqttClientId, "", "");
    }
    /**
     * 建立mqtt连接
     * 
     * @param serverURL 连接服务器地址
     * @param clientId mqtt接入客户端ID
     * @param username mqtt接入用户名
     * @param password mqtt接入密码
     */
    protected void connect(String serverURL, String clientId, String username, String password) {
        try {
            MemoryPersistence persistence = new MemoryPersistence();
            sampleClient = new MqttClient(serverURL, clientId, persistence);
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setMqttVersion(4);// MQTT 3.1.1
            connOpts.setUserName(username);// 用户名
            connOpts.setPassword(password.toCharArray());// 密码
            connOpts.setSocketFactory(createSSLSocket()); // 使用TLS,需要下载根证书root.crt,设置securemode=2
            connOpts.setCleanSession(false); // 不清理离线消息,qos=1的消息在设备离线期间会保存在云端
            connOpts.setAutomaticReconnect(false); // 作为demo关闭自动重连,生产环境强烈建议开启自动重连
            connOpts.setKeepAliveInterval(300); // 设置心跳,建议300秒
            // 先设置回调,如果是先connect后设置回调,可能会导致消息到达时回调还没准备好,这样消息就丢失了
            sampleClient.setCallback(new MqttCallback() {
                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    // 只处理X.509认证返回信息
                    if (AUTH_TOPIC.equals(topic)) {
                        JSONObject json = JSONObject
                                .parseObject(new String(message.getPayload(), StandardCharsets.UTF_8));
                        productKey = json.getString("productKey");
                        deviceName = json.getString("deviceName");
                    } else {
                        // 其他下行消息处理,强烈建议另起线程处理,以免回调堵塞
                    }
                }
                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                }
                @Override
                public void connectionLost(Throwable cause) {
                }
            });
            System.out.println("Connecting to broker: " + serverURL);
            sampleClient.connect(connOpts);
            System.out.print("Connected: clientId=" + clientId);
            System.out.println(",username=" + username + ",password=" + password);
        } catch (MqttException e) {
            System.out.print("connect failed: clientId=" + clientId);
            System.out.println(",username=" + username + ",password=" + password);
            System.out.println("reason " + e.getReasonCode());
            System.out.println("msg " + e.getMessage());
            System.out.println("loc " + e.getLocalizedMessage());
            System.out.println("cause " + e.getCause());
            System.out.println("excep " + e);
            e.printStackTrace();
        } catch (Exception e) {
            System.out.print("connect exception: clientId=" + clientId);
            System.out.println(",username=" + username + ",password=" + password);
            System.out.println("msg " + e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * 发布消息,默认qos=0
     * 
     * @param topic 发布消息的topic
     * @param payload 发布的消息内容
     */
    public void publish(String topic, String payload) {
        byte[] content = payload.getBytes(StandardCharsets.UTF_8);
        publish(topic, 0, content);
    }
    /**
     * 发布消息
     * 
     * @param topic 发布消息的topic
     * @param qos 消息等级,平台支持qos=0和qos=1,不支持qos=2
     * @param payload 发布的消息内容
     */
    public void publish(String topic, int qos, byte[] payload) {
        MqttMessage message = new MqttMessage(payload);
        message.setQos(qos);
        try {
            sampleClient.publish(topic, message);
            System.out.println("Message published: topic=" + topic + ",qos=" + qos);
        } catch (MqttException e) {
            System.out.println("publish failed: topic=" + topic + ",qos=" + qos);
            System.out.println("reason " + e.getReasonCode());
            System.out.println("msg " + e.getMessage());
            System.out.println("loc " + e.getLocalizedMessage());
            System.out.println("cause " + e.getCause());
            System.out.println("excep " + e);
            e.printStackTrace();
        }
    }
    protected SSLSocketFactory createSSLSocket() throws Exception {
        // CA根证书,可以从官网下载 https://help.aliyun.com/document_detail/73742.html
        // 设备证书,可以从控制台设备信息下载
        // CA certificate is used to authenticate server
        InputStream in = IotMqttClientWithAuthByX509.class.getResourceAsStream("/root.crt");
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate ca = cf.generateCertificate(in);
        in.close();
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);
        // client key and certificates are sent to server so it can authenticate us
        InputStream certIn = IotMqttClientWithAuthByX509.class.getResourceAsStream(certPath);
        CertificateFactory certCf = CertificateFactory.getInstance("X.509");
        Certificate certCa = certCf.generateCertificate(certIn);
        certIn.close();
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(null, null);
        ks.setCertificateEntry("certificate", certCa);
        PrivateKey privateKey = getPrivateKey(privateKeyPath);
        ks.setKeyEntry("private-key", privateKey, privateKeyPassword.toCharArray(), new Certificate[] { certCa });
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(ks, privateKeyPassword.toCharArray());
        SSLContext context = SSLContext.getInstance("TLSV1.2");
        context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        SSLSocketFactory socketFactory = context.getSocketFactory();
        return socketFactory;
    }
    private PrivateKey getPrivateKey(String path) throws Exception {
        byte[] buffer = Base64.decodeBase64(getPem(path));
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }
    private String getPem(String path) throws Exception {
        InputStream in = IotMqttClientWithAuthByX509.class.getResourceAsStream(path);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String readLine = null;
        StringBuilder sb = new StringBuilder();
        while ((readLine = br.readLine()) != null) {
            if (readLine.charAt(0) == '-') {
                continue;
            } else {
                sb.append(readLine);
                sb.append('\r');
            }
        }
        in.close();
        return sb.toString();
    }
    /**
     * 1、设备证书从控制台设备列表页面下载,下载包包含cer和key两个文件 <br>
     * 2、私钥是pkcs1格式的,java原生ssl需要转成pkcs8格式使用 <br>
     * 3、mqttClientId连接参数只需要也必需要填写 |securemode=2|,表示只能使用TLS <br>
     * 4、mqttUsername和mqttPassword填写"",因为使用证书认证就不需要这两个参数了 <br>
     * 5、连接成功后会下发pk+dn信息到/ext/auth/identity/response,用于组装topic进行消息收发 <br>
     * 
     * @param args
     */
    public static void main(String[] args) {
        IotMqttClientWithAuthByX509 client = new IotMqttClientWithAuthByX509();
        // 填写设备证书路径信息
        client.connect("您的设备证书路径", "您的证书私钥路径", "");
        // 连接之后,睡两秒,保证pk+dn已经下发,不然消息收发是topic的pk+dn字段是空的
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 发送消息验证连接是否成功
        String updateTopic = "/" + productKey + "/" + deviceName + "/user/update";
        client.publish(updateTopic, "hello mqtt with X.509 auth");
    }
}


相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
数据采集 前端开发 开发工具
Android平台GB28181设备接入端PTZ对接详解
上一篇blog“Android平台GB28181设备接入模块之球机/云台控制探究”谈到,Android平台做国标GB28181设备接入端的时候,PTZ控制要不要处理?如果处理,难度大不大?
150 0
|
算法 程序员 容器
工行银企互联接入详解(2)--下载证书
本文目录 1. 下载NC3.1 2. 启动NC 3. 进入下载证书页面 4. 配置参数 5. 下载证书 6. 其他
409 0
工行银企互联接入详解(2)--下载证书
|
3月前
|
存储 网络协议 Serverless
函数计算产品使用问题之第三方软件链接阿里云SD出现无法绘图,是什么导致的
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
22天前
|
监控 Java 开发工具
如何快速对接Android平台GB28181接入模块(SmartGBD)
大牛直播SDK推出的Android平台GB28181接入SDK(SmartGBD),可实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景,可能是业内为数不多功能齐全性能优异的商业级水准GB28181接入SDK。
|
4月前
|
存储 人工智能 监控
智慧工地云服务平台源码 PC+APP+数据大屏
智慧工地系统利用移动互联、物联网、云计算、大数据等新一代信息技术,彻底改变传统施工现场各参建方的交互方式、工作方式和管理模式,为建设集团、施工企业、监理单位、设计单位、政府监管部门等提供一揽子工地现场管理信息化解决方案。
60 1
|
编解码 监控 开发工具
Android平台GB28181接入模块技术接入说明
今天,我们主要讲讲Android平台GB28181接入模块的技术对接,Android平台GB28181接入模块设计的目的,可实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如智能监控、智慧零售、智慧教育、远程办公、生产运输、智慧交通、车载或执法记录仪等场景。
134 1
|
开发工具 云计算 开发者
IOS证书制作和IPA文件提交至开发者中心的极简工具
在没有Mac电脑或对Xcode等开发工具不熟悉的情况下,如何快速完成IOS证书制作和IPA文件提交至开发者中心一直是一个难题。但是现在,有了初雪云提供的极简工具,您可以轻松实现这两个任务,无需Mac电脑,无需繁琐的网页操作,简单几步即可完成
73 0
|
Web App开发 Android开发 开发者
Andorid平台GB28181设备接入端如何生成黑帧并推送至国标平台
我们在做Android平台GB28181设备接入模块的时候,遇到这样的需求,做移动对讲的时候,是不需要视频数据的,但是国标平台侧,没有视频的话,大多平台又无法播纯音频打包的数据(网页端大多基于http-flv或webrtc实现),基于此,我们做了个简单的处理,通过Bitmap生成个32*32的黑帧,然后,确保上行的音视频数据都有,但是由于视频系黑帧数据,几乎不占用带宽。
|
安全 网络安全 数据安全/隐私保护
IOS证书制作教程:从新增证书开始
这个密码不是账号密码,而是一个保护证书的密码,是p12文件的密码,此密码设置后没有其他地方可以找到,忘记了只能删除证书重新制作,所以请务必记住密码。还有为了安全起见,密码不要太简单。
|
Web App开发 JavaScript Java
Sonic 开源移动端云真机测试平台 - 设备中心接入安卓设备实例演示,Agent端服务部署过程详解(上)
Sonic 开源移动端云真机测试平台 - 设备中心接入安卓设备实例演示,Agent端服务部署过程详解
452 0