openssl 生成多域名 多IP 的数字证书
openssl.cnf 文件内容:
![]()
[req] default_bits = 2048 distinguished_name = req_distinguished_name copy_extensions = copy req_extensions = req_ext x509_extensions = v3_req prompt = no [req_distinguished_name] countryName = CN stateOrProvinceName = GuangDong localityName = ShenZhen organizationName = lc commonName = CA [req_ext] basicConstraints = CA:FALSE subjectAltName = @alt_names [v3_req] basicConstraints = CA:FALSE subjectAltName = @alt_names [alt_names] IP.1 = 192.168.10.31 IP.2 = 192.168.10.32 IP.3 = 192.168.10.33 DNS.1 = 192.168.10.2 DNS.2 = 202.96.134.133
![]()
生成证书
工具是用的:windows平台 Win64OpenSSL-3_2_0.exe 或 Win64OpenSSL_Light-3_2_0.exe (建议用:Win64OpenSSL-3_2_0.exe )
OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023)
![]()
根证书: openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.pem -subj "/C=CN/ST=GuangDong/O=EMQX/CN=Client" 服务端证书: openssl genrsa -out emqx.key 2048 openssl req -new -key emqx.key -config openssl.cnf -out emqx.csr openssl x509 -req -in emqx.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out emqx.pem -days 3650 -sha256 -extensions v3_req -extfile openssl.cnf 客户端证书: openssl genrsa -out client.key 2048 openssl req -new -key client.key -out client.csr -subj "/C=CN/ST=GuangDong/O=EMQX/CN=Client" openssl x509 -req -days 3650 -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem 校验证书的有效性: openssl verify -CAfile ca.pem emqx.pem openssl verify -CAfile ca.pem client.pem
![]()
常见错误:
Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: IP: 192.168.10.32 is not in the cert's list:
Error: self signed certificate in certificate chain
Error: Connection refused: Not authorized # 没有设置用户名密码
Error: unable to verify the first certificate
加密认证算法:
![]()
package com.lc.common.mqtt.utils;import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;/*** @author Charley* @date 2022/12/05* @description*/
@Component
public class SSLUtils {@javax.annotation.Resourceprivate ResourceLoader resourceLoader;public SSLSocketFactory getSingleSocketFactory(InputStream caCrtFileInputStream) throws Exception {Security.addProvider(new BouncyCastleProvider());X509Certificate caCert = null;BufferedInputStream bis = new BufferedInputStream(caCrtFileInputStream);CertificateFactory cf = CertificateFactory.getInstance("X.509");while (bis.available() > 0) {caCert = (X509Certificate) cf.generateCertificate(bis);}KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());caKs.load(null, null);caKs.setCertificateEntry("cert-certificate", caCert);TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());tmf.init(caKs);SSLContext sslContext = SSLContext.getInstance("TLSv1.2");sslContext.init(null, tmf.getTrustManagers(), null);return sslContext.getSocketFactory();}public SSLSocketFactory getSocketFactory(final String caCrtFile,final String crtFile, final String keyFile, final String password)throws Exception {Security.addProvider(new BouncyCastleProvider());// load CA certificateX509Certificate caCert = null;// FileInputStream fis = new FileInputStream(caCrtFile);BufferedInputStream bis = new BufferedInputStream(resourceLoader.getResource(caCrtFile).getInputStream());CertificateFactory cf = CertificateFactory.getInstance("X.509");while (bis.available() > 0) {caCert = (X509Certificate) cf.generateCertificate(bis);}// load client certificate//bis = new BufferedInputStream(new FileInputStream(crtFile));bis = new BufferedInputStream(resourceLoader.getResource(crtFile).getInputStream());X509Certificate cert = null;while (bis.available() > 0) {cert = (X509Certificate) cf.generateCertificate(bis);}// load client private key
// PEMParser pemParser = new PEMParser(new FileReader(keyFile));
// Object object = pemParser.readObject();
// JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
// KeyPair key = converter.getKeyPair((PEMKeyPair) object);
// pemParser.close();// PEMParser pemParser =new PEMParser(new InputStreamReader(new FileInputStream(keyFile)));PEMParser pemParser =new PEMParser(new InputStreamReader(resourceLoader.getResource(keyFile).getInputStream()));Object obj = pemParser.readObject();JcaPEMKeyConverter converter = new JcaPEMKeyConverter();PrivateKey privateKey = converter.getPrivateKey((PrivateKeyInfo) obj);// CA certificate is used to authenticate serverKeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());caKs.load(null, null);caKs.setCertificateEntry("ca-certificate", caCert);TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");tmf.init(caKs);// client key and certificates are sent to server, so it can authenticateKeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());ks.load(null, null);ks.setCertificateEntry("certificate", cert);ks.setKeyEntry("private-key", privateKey, password.toCharArray(),new java.security.cert.Certificate[]{cert});KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());kmf.init(ks, password.toCharArray());// finally, create SSL socket factorySSLContext context = SSLContext.getInstance("TLSv1.2");context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);return context.getSocketFactory();}
}
![]()
mqq5:
![]()
package com.lc.common.mqtt.mqttv5;import cn.hutool.core.util.IdUtil;
import com.lc.common.mqtt.config.MqttConfig;
import com.lc.common.mqtt.utils.SSLUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.mqttv5.client.MqttConnectionOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.outbound.Mqttv5PahoMessageHandler;
import org.springframework.integration.mqtt.support.MqttHeaderMapper;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import javax.annotation.Resource;@Configuration
@Slf4j
public class Mqtt5Client {@ResourceMqttConfig mc;@Resourceprivate SSLUtils sslUtils;@Resourceprivate Mqtt5MessageReceiver mqttMessageReceiver;/*** (生产者) mqtt消息出站通道,用于发送出站消息* @return*/@Beanpublic MessageChannel mqttOutputChannel5() {return new DirectChannel();}/*** (消费者) mqtt消息入站通道,订阅消息后消息进入的通道。* @return*/@Beanpublic MessageChannel mqttInputChannel5() {return new DirectChannel();}public MqttConnectionOptions getOptions() {MqttConnectionOptions options = new MqttConnectionOptions();options.setServerURIs(mc.getServices());options.setUserName(mc.getUser());options.setPassword(mc.getPassword().getBytes());options.setReceiveMaximum(mc.getMaxInflight());options.setKeepAliveInterval(mc.getKeepAliveInterval());// 重连设置options.setAutomaticReconnect(mc.isAutomaticReconnect());options.setMaxReconnectDelay(mc.getMaxReconnectDelay());options.setAutomaticReconnectDelay(mc.getV5AutomaticReconnectMinDelay(), mc.getV5AutomaticReconnectMaxDelay());// 会话设置options.setCleanStart(mc.isV5CleanStart());options.setSessionExpiryInterval(mc.getV5SessionExpiryInterval());// 超时设置options.setConnectionTimeout(mc.getConnectionTimeout());try {options.setSocketFactory(sslUtils.getSocketFactory("classpath:ca.pem","classpath:client.pem","classpath:client.key",""));} catch (Exception e) {e.printStackTrace();}return options;}/*** 生产者* @return*/@Bean@ServiceActivator(inputChannel = "mqttOutputChannel5")public MessageHandler mqttOutbound5() {String clientId = mc.getV5ProducerId() + "_" + IdUtil.getSnowflakeNextId();;Mqttv5PahoMessageHandler messageHandler = new Mqttv5PahoMessageHandler(getOptions(), clientId);messageHandler.setHeaderMapper(new MqttHeaderMapper());// 设置异步不阻塞messageHandler.setAsync(false);// 设置QosmessageHandler.setDefaultQos(mc.getQos());return messageHandler;}/*** MQTT消息订阅绑定(消费者)* @return*/@Beanpublic MessageProducer channelInbound5(MessageChannel mqttInputChannel5) {String clientId = mc.getV5ConsumerId() + "_" + IdUtil.getSnowflakeNextId();;MyMqttv5PahoMessageDrivenChannelAdapter adapter = new MyMqttv5PahoMessageDrivenChannelAdapter(getOptions(), clientId, mc.getV5DefaultTopic());adapter.setCompletionTimeout(mc.getCompletionTimeout());adapter.setPayloadType(String.class);adapter.setQos(mc.getQos());adapter.setOutputChannel(mqttInputChannel5);return adapter;}/*** MQTT消息处理器(消费者)* @return*/@Bean@ServiceActivator(inputChannel = "mqttInputChannel5")public MessageHandler mqttMessageHandler5() {return mqttMessageReceiver;}
}
![]()
mqtt3
![]()
package com.lc.common.mqtt.mqttv3;import cn.hutool.core.util.IdUtil;
import com.lc.common.mqtt.utils.SSLUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import com.lc.common.mqtt.config.MqttConfig;
import javax.annotation.Resource;@Configuration
@Slf4j
public class Mqtt3Client {@Resourceprivate MqttConfig mc;@Resourceprivate SSLUtils sslUtils;@Resourceprivate Mqtt3MessageReceiver mqttMessageReceiver;/*** (生产者) mqtt消息出站通道,用于发送出站消息* @return*/@Beanpublic MessageChannel mqttOutputChannel3() {return new DirectChannel();}/*** (消费者) mqtt消息入站通道,订阅消息后消息进入的通道。* @return*/@Beanpublic MessageChannel mqttInputChannel3() {return new DirectChannel();}public MqttConnectOptions getOptions() {MqttConnectOptions options = new MqttConnectOptions();options.setServerURIs(mc.getServices());options.setUserName(mc.getUser());options.setPassword(mc.getPassword().toCharArray());options.setMaxInflight(mc.getMaxInflight());options.setKeepAliveInterval(mc.getKeepAliveInterval());// 重连设置options.setAutomaticReconnect(mc.isAutomaticReconnect());options.setMaxReconnectDelay(mc.getMaxReconnectDelay());// options.setAutomaticReconnectDelay(automaticReconnectMinDelay, automaticReconnectMaxDelay);// 会话设置options.setCleanSession(mc.isV3CleanSession());// 超时设置options.setConnectionTimeout(mc.getConnectionTimeout());// 设置遗嘱消息 qos 默认为 1 retained 默认为 falseoptions.setWill("willTopic","与服务器断开连接".getBytes(),0,false);try {options.setSocketFactory(sslUtils.getSocketFactory("classpath:ca.pem","classpath:client.pem","classpath:client.key",""));} catch (Exception e) {e.printStackTrace();}return options;}/*** 生产者* @return*/@Bean@ServiceActivator(inputChannel = "mqttOutputChannel3")public MessageHandler mqttOutbound3() {String clientId = mc.getV3ProducerId() + "_" + IdUtil.getSnowflakeNextId();DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory() ;factory.setConnectionOptions(getOptions());MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(clientId, factory);// 设置异步不阻塞messageHandler.setAsync(true);// 设置QosmessageHandler.setDefaultQos(mc.getQos());return messageHandler;}/*** MQTT消息订阅绑定(消费者)* @return*/@Beanpublic MessageProducer channelInbound3(MessageChannel mqttInputChannel3) {String clientId = mc.getV3ConsumerId() + "_" + IdUtil.getSnowflakeNextId();;DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();factory.setConnectionOptions(getOptions());MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(clientId, factory, mc.getV3DefaultTopic());adapter.setCompletionTimeout(mc.getCompletionTimeout());adapter.setRecoveryInterval(mc.getV3RecoveryInterval());adapter.setConverter(new DefaultPahoMessageConverter());adapter.setQos(mc.getQos());adapter.setOutputChannel(mqttInputChannel3);return adapter;}/*** MQTT消息处理器(消费者)* @return*/@Bean@ServiceActivator(inputChannel = "mqttInputChannel3")public MessageHandler mqttMessageHandler3() {return mqttMessageReceiver;}
}
![]()
0
0
« 上一篇: SSL/TSL 总结
» 下一篇: npm 错误,ERESOLVE unable to resolve dependency tree 解决方案
相关文章:
openssl 生成多域名 多IP 的数字证书
openssl.cnf 文件内容: [req] default_bits 2048 distinguished_name req_distinguished_name copy_extensions copy req_extensions req_ext x509_extensions v3_req prompt no [req_distinguished_name] countryName CN stateOrProvinceName GuangDong l…...
电影评论|基于springBoot的电影评论网站设计与实现(附项目源码+论文+数据库)
私信或留言即免费送开题报告和任务书(可指定任意题目) 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取: 一、摘要 随着信息技术在管理上越来越深入而广泛的应用,…...
【C++】虚函数
一、什么是虚函数 在类的成员函数前加上virtual关键字,这个函数就是虚函数。 虚函数的所用就是完成多态。多态示例如下: class A {public:virtual void func()//虚函数{cout << "A" << endl;}void ftwo()//普通函数{cout <&…...
esxi虚拟机启用cbt备份(增量备份)
在虚拟机中启用CBT 1.关闭虚拟机。 右键点按虚拟机,Edit Settings-VM Options-Advanced-Configuration Parameters-Edit Configuration- Add parameters,添加ctkEnabled参数,并将其值设置为true。 Add parameters,添加scsi0:0…...
mysql 8.0 时间维度表生成(可运行)
文章目录 mysql 8.0 时间维度表生成实例时间维度表的作用时间维度表生成技术细节使用时间维度表的好处 mysql 8.0 时间维度表生成实例 时间维度表的作用 dim_times(时间维度表)在数据仓库(Data Warehouse)中的作用至关重要。作为…...
打造高效实时数仓,从Hive到OceanBase的经验分享
本文作者:Coolmoon1202,大数据高级工程师,专注于高性能软件架构设计 我们的业务主要围绕出行领域,鉴于初期采用的数据仓库方案面临高延迟、低效率等挑战,我们踏上了探索新数仓解决方案的征途。本文分享了我们在方案筛选…...
15.3 JDBC数据库编程
15.3 JDBC数据库编程 15.3.1 创建数据库和表 创建一个名为webstore的数据库,并向其中添加数据,代码如下: 1.创建数据库 CREATE TABLE products( id int PRIMARY KEY, pname VARCHAR(20) brand VARCHAR(20), price FLOAT(7,2), stock SMALLINT, ) …...
SSH公私钥后门从入门到应急响应
目录 1. SSH公私钥与SSH公私钥后门介绍 1.1 SSH公私钥介绍 1.1.1 公钥和私钥的基本概念 1.1.2 SSH公私钥认证的工作原理(很重要) 1.2 SSH公私钥后门介绍 2. 如何在已拿下控制权限的主机创建后门 2.1 使用 Xshell 生成公钥与私钥 2.2 将公钥上传到被需要被植入后门的服务…...
服务器数据恢复—Linux操作系统环境下网站数据的恢复案例
服务器数据恢复环境: 一台linux操作系统服务器上跑了几十个网站,服务器上只有一块SATA硬盘。 服务器故障: 服务器突然宕机,尝试再次启动失败。将硬盘拆下检测,发现存在坏扇区。找当地一家数据恢复公司处理后ÿ…...
开放式耳机是怎么样的?开放式耳机的优缺点分析?
开放式耳机作为一种独特的耳机类型,因其独特设计和使用体验受到了许多用户的喜爱。了解开放式耳机的优缺点有助于大家更好地选择适合自己需求的耳机。以下是开放式耳机的一些主要优点和缺点分析: 优点 l 舒适度高 开放式耳机的设计通常更加轻盈&#…...
HDMI色块移动——FPGA学习笔记13
一、方块移动原理 二、实验任务 使用FPGA开发板上的HDMI接口在显示器上显示一个不停移动的方块,要求方块移动到边界处时能够改变移动方向。显示分辨率为800*480,刷新速率为90hz。(480p分辨率为800*480,像素时钟频率Vga_clk 800x4…...
MySQL中去除重复
除去相同的行 SELECT DISTINCT 列名 FROM 表名; 示例:查询employees表,显示唯一的部门ID select distinct department_id from employees;...
【C++】vector容器的基本使用
一、vector是什么 vector是STL第一个正式的容器,它的底层其实就是动态数组,插入数据时当容量满了会自动扩容,它和string差不多,不同的之处之一在于vector本身是一个模板,它这个容器中可以存放各种各样的类型的数据&am…...
【强化学习系列】Gym库使用——创建自己的强化学习环境2:拆解官方标准模型源码/规范自定义类+打包自定义环境
目录 一、 官方标准环境的获取与理解 二、根据官方环境源码修改自定义 1.初始化__init__() 2.重置环境 reset() 三、打包环境 1.注册与创建自定义环境 2.环境规范化 在本文的早些时候,曾尝试按照自己的想法搭建自定义的基于gym强化学习环境。 【强化学习系列】Gy…...
PyQt5实现按钮选择文件夹及文件夹
目录 1、选择文件夹并显示 2、选择文件 3、选择多个文件 4、设置保存文件路径 1、选择文件夹并显示 from PyQt5 import QtWidgetsdirectory QtWidgets.QFileDialog.getExistingDirectory(None, "选取文件夹", "./") # 起始路径 print(directory) 2…...
Gin渲染
HTML渲染 【示例1】 首先定义一个存放模板文件的 templates文件夹,然后在其内部按照业务分别定义一个 posts 文件夹和一个 users 文件夹。 posts/index.tmpl {{define "posts/index.tmpl"}} <!DOCTYPE html> <html lang"en">&…...
前端——JS基础
定义变量:let / var 字符串 字符串拼接: 字符串和数字拼:您.... 25 ; 这个25会转成字符串再拼接 字符串和数组拼:10以内的质数有: [2,3,5,7] > 10以内的质数有:2,3,5,7 字符串长度:leng…...
MATLAB入门教程
MATLAB安装教程可参考链接:matlab怎么安装 matlab安装教程-电脑软件-PHP中文网 1.MATLAB的工作环境 (1)命令窗(command window) 是对MATLAB进行操作的主要载体。默认情况下,启动MATLAB时就打开命令窗。MATLAB的所有所数…...
muduo - 概要简述
作者:陈硕 编程语言:C 架构模式:Reactor 代码链接:GitHub - chenshuo/muduo: Event-driven network library for multi-threaded Linux server in C11 设计自述:https://www.cnblogs.com/Solstice/archive/2010/08…...
Selenium点击元素的方法
前言 点击方法在web自动化测试中经常用到,下面就来介绍一下selenium常用和不常用的点击方法; 1、常用方法 1.1、使用 click() 方法: 这是最简单和最常用的方法。通过选中要点击的元素,然后使用 click() 方法来触发点击事件。 示例代码: element = self.driver.find_e…...
基于Arduino与应变片传感器的高精度厨房电子秤DIY全攻略
1. 项目概述:用Arduino打造一台高精度厨房电子秤作为一个喜欢在厨房里折腾的硬件爱好者,我经常遇到需要精确称量食材的场合。市面上的电子秤要么精度不够,要么价格不菲,要么功能单一。于是,我萌生了自己动手做一台的想…...
举一个具体例子说明为什么索引不是越多越好,举具体字段
文章目录1. 核心舞台:笔记表 (t_note) 结构设计🚨 错误的操作:2. 结合具体字段,拆解三大翻车现场现场一:给 view_count(浏览量)加索引 —— 导致写放大,拖垮数据库现场二:…...
Taotoken如何帮助教育科技产品实现个性化学习辅导
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken如何帮助教育科技产品实现个性化学习辅导 1. 场景与挑战 教育科技公司在开发个性化学习助手时,常常面临一个核…...
基于PIC32单片机实现Android USB音频转SPDIF输出的DIY方案
1. 项目概述:为Android设备打造一个高保真SPDIF音频接口作为一名长期折腾嵌入式音频和家庭影院的玩家,我经常遇到一个痛点:手头那些性能不错的Android手机或平板,其内置的3.5mm耳机孔或者USB-C口的音频输出质量,在连接…...
8款网盘直链下载助手:彻底告别限速烦恼,实现高速下载自由
8款网盘直链下载助手:彻底告别限速烦恼,实现高速下载自由 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移…...
终极崩坏星穹铁道自动化指南:3分钟掌握解放双手的智能游戏伴侣
终极崩坏星穹铁道自动化指南:3分钟掌握解放双手的智能游戏伴侣 【免费下载链接】StarRailAssistant 崩坏:星穹铁道自动化 | 崩坏:星穹铁道自动锄大地 | 崩坏:星穹铁道锄大地 | 自动锄大地 | 基于模拟按键 项目地址: https://git…...
Video2X专业级AI视频增强实战指南:GPU加速无损放大的深度技术解析
Video2X专业级AI视频增强实战指南:GPU加速无损放大的深度技术解析 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_Trendi…...
告别手动映射!用AD域控组策略批量给员工电脑挂载共享盘(Windows Server 2016实战)
企业级共享存储自动化部署指南:基于AD域控的组策略实战每当新员工入职或部门调整时,IT管理员最头疼的莫过于重复配置几十台电脑的共享盘映射。财务部需要访问M盘的报表目录,市场部要连接N盘的设计素材,而手动设置不仅效率低下&…...
初创团队如何借助Taotoken以低成本快速验证AI产品创意
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 初创团队如何借助Taotoken以低成本快速验证AI产品创意 对于资源有限的初创团队而言,验证一个AI产品创意的核心挑战往往…...
亿万富翁不再相信比特币
亿万富翁首次公开称不再相信比特币的「数字黄金」叙事。对比特币而言,或许是一个重要转折点。5月22日,亿万富翁投资者马克库班表示, 在对比特币作为抵御法币疲软和地缘政治不稳定对冲工具的作用失去信心后, 他已经卖掉大部分比特币持仓。净资产约为100亿…...
