GBase8a SSL 配置

GBase8a SSL 配置

GBase8a MPP Cluster 支持 SSL 标准协议, SSL 协议是一种安全性更高的协议标准, 它加入了数字签名和数字证书来实现客户端和服务器的双向身份验证,保证了通信双方更加安全的数据传输。


配置客户端使用 SSL 安全连接的方式连接到 GBase8a MPP Cluster 数据库集群的配置总体流程如下:

生成 SSL 连接证书 ==> server 配置 ==> client 配置


1. 生成 SSL 连接证书
在集群 server 端的系统中, 根据需要选择生成 SSL 密钥的目录, 下面以 GBase8a 的安装目录下的 ssl 目录保存相关文件为例进行配置说明。

1.1 在 server 上操作生成 server 端的密钥和证书

step1:
# su - gbase
$ mkdir -p /opt/gbase8a/ssl     # /opt/gbase8a 是我的GBase8a安装目录,在安装目录下有权限创建 ssl 目录
$ cd /opt/gbase8a/ssl

后续的证书也秘钥生成过程中,需要填写一些信息,我除了 Country Name 填写 CN,password 填写 123456 外,其他都未填写直接回车了,项目中可以根据实际情况填写。

step2:
生成 ca-cert.pem, 需要填写 Country Name 等信息
$ openssl req -sha1 -new -x509 -nodes -days 3650 -keyout ca-key.pem > ca-cert.pem 

You are about to be asked to enter information that will be incorporated into your certificate request.
......
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
执行完毕,会生成两个文件:ca-cert.pem 和 ca-key.pem


step3:
生成服务端密钥, 同样填写一些信息, password 部分( A challenge password []: ) 建议填写复杂一些的密码
$ openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem > server-req.pem 

Generating a 2048 bit RSA private key
......
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:
执行完毕,会生成两个文件:server-key.pem 和 server-req.pem

step4:
将 server-key.pem 导出为 RSA 类型:
$ openssl rsa -in server-key.pem -out server-key.pem

step5:
生成服务端证书 server-cert.pem
$ openssl x509 -sha1 -req -in server-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem 


ssl 证书相关查看命令:
openssl rsa -in server-key.pem -text          #查看证书私钥文件中的私钥和公钥信息
openssl x509 -in server-cert.pem -noout -text #查看证书详细信息

1.2 在 server 上操作生成 client 端的密钥和证书

step1:
在同一目录下, 生成 client 端的密钥和证书, 生成密钥, 输入信息与 server 端相同。
$ openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem > client-req.pem 
Generating a 2048 bit RSA private key
......
Country Name (2 letter code) [XX]:CA
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:
会生成两个文件:client-key.pem 和 client-req.pem

step2:
将 client-key.pem 导出为 RSA 类型
$ openssl rsa -in client-key.pem -out client-key.pem 

step3:
生成 client-cert.pem
$ openssl x509 -sha1 -req -in client-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem 


前面所有过程总共生成的8个文件:
ca-key.pem:CA 私钥, 用于生成服务器端/客户端的数字证书;
ca-cert.pem:CA 证书,用于生成服务器端/客户端的数字证书;
server-key.pem:服务器端的 RSA 私钥;
server-req.pem:服务器端的证书请求文件,用于生成服务器端的数字证书;
server-cert.pem:服务器端的数字证书;
client-key.pem:客户端的 RSA 私钥;
client-req.pem:客户端的证书请求文件,用于生成客户端的数字证书;
client-cert.pem:客户端的数字证书。


2. server 配置
step1:
修改集群配置文件 gbase_8a_gcluster.cnf, 在 [gbased] 里添加 ssl 信息。 以路径 /opt/gbase8a/ssl 为例, 添加示例如下:
$ vi $GCLUSTER_BASE/config/gbase_8a_gcluster.cnf
[client]
port=5258
socket=/tmp/gcluster_5258.sock
connect_timeout=43200
#default-character-set=gbk
default-character-set=utf8

[gbased]
basedir = /opt/gcluster/server
datadir = /opt/gcluster/userdata/gcluster
socket=/tmp/gcluster_5258.sock
pid-file = /opt/gcluster/log/gcluster/gclusterd.pid
#default-character-set=gbk
default-character-set=utf8

# server cfg for ssl
ssl-ca=/opt/gbase8a/ssl/ca-cert.pem
ssl-cert=/opt/gbase8a/ssl/server-cert.pem
ssl-key=/opt/gbase8a/ssl/server-key.pem

log-error
port=5258
core-file


step2:
重启集群,查看配置是否成功
$ gcluster_services all restart

step3:
执行 gccli, 登录集群
$ gccli -ugbase -p

step4:
查看 ssl 参数状态, 配置成功则显示为“YES”。
gbase> show variables like 'have_%ssl';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_openssl  | YES   |
| have_ssl      | YES   |
+---------------+-------+


3. client 配置

集群 client 的配置,直接在 client 端的 Linux 上配置。

step1:
将 server 端生成的 ca-cert.pem,client-key.pem,client-cert.pem 文件拷贝到 client 端,
修改 client 端的集群配置文件 gbase_8a_gcluster.cnf,在 [client] 里添加 ssl 信息, 以路径 /opt/gbase8a/ssl 为例:
注意:如果客户端是独立安装的 gccli 工具客户端,则配置文件位于:gccli 安装目标路径/config/gbase_8a_gcluster.cnf

$ vi $GCLUSTER_BASE/config/gbase_8a_gcluster.cnf
[client]
port=5258
socket=/tmp/gcluster_5258.sock
connect_timeout=43200
#default-character-set=gbk
default-character-set=utf8

# client cfg for ssl
ssl-ca=/opt/gbase8a/ssl/ca-cert.pem
ssl-cert=/opt/gbase8a/ssl/client-cert.pem
ssl-key=/opt/gbase8a/ssl/client-key.pem

step2:
通过 client 端远程访问 server 并执行 status 命令查看当前连接是否为 ssl 加密连接(ssl 部分显示有 “Cipher in use”,如果未走ssl则显示"Not in use")
$ gccli -h192.168.1.162 -ugbase -p 
gbase> status

如果是单独创建的 gbasessl 用户,则执行:
$ gccli -h192.168.1.162 -ugbasessl -p -Dtestdb01

gbase> status
--------------
/home/frank/gccli/gcluster/server/bin/gbase ver 9.5.3.14.121230, for unknown-linux-gnu (x86_64) using readline 6.3

Connection id:          18
Current database:       testdb01
Current user:           gbasessl@192.168.1.82
SSL:                    Cipher in use is DHE-RSA-AES256-SHA ==> 说明当前连接时SSL加密连接
Current pager:          stdout
......


step3:
如果 client 端没有进行上述 ssl 配置, 则仍然会按默认方式(非ssl)连接 server。如果想要强制用户必须使用 ssl 连接,则可以通过如下方式配置来强制指定的用户必须使用 ssl 连接:


gbase> grant all on testdb01.* to gbase require ssl

gbase用于原来已经在使用了,为了不影响原来的使用,gbase用户连接方式在服务器端不做强制要求配置,我直接单独创建一个新用户 gbasessl 来指定必须SSL连接(grant ...... require ssl):
gbase> create user gbasessl identified by '1q2w3e';
gbase> grant all on testdb01.* to gbasessl require ssl;
gbase> quit;
$ gccli -h192.168.1.162 -ugbasessl -p -Dtestdb01
gbase> status

查看用户是否备服务器配置为强制SSL连接,可以通过查询系统表 gbase.user 来看:

$ gccli -h192.168.1.162 -ugbase -p -Dtestdb01
gbase> select user,ssl_type from gbase.user; 
+-----------------+----------+
| user            | ssl_type |
+-----------------+----------+
| root            |          |
| gbase           |          |
| gbasessl        | ANY      |
+-----------------+----------+
为空代表没有强制必须使用SSL连接,不为空(ANY | X509 | SPECIFIED)都代表必须使用SSL连接。


ssl 连接参数:
--skip-ssl:客户端强制使用非SSL连接
--ssl:客户端强制使用SSL连接
如果不加参数,默认优先使用非SSL连接


gbasessl 账号连接测试(创建用户时指定了 require ssl):

$ gccli -h192.168.1.162 -ugbasessl -Dtestdb01 -p --skip-ssl
客户端指定非SSL(--skip-ssl),我 gbasessl 服务器强制ssl(require ssl),所以会连接失败

$ gccli -h192.168.1.162 -ugbasessl -Dtestdb01 -p 
gbase> status;
客户端不指定,连接成功,为SSL

$ gccli -h192.168.1.162 -ugbasessl -Dtestdb01 -p --ssl
gbase> status;
客户端指定SSL(--ssl),连接成功,为SSL


gbase 账号连接测试(默认未指定 require ssl)
gbase账号服务器没有设置强制ssl

$ gccli -h192.168.1.162 -ugbase -Dtestdb01 -p --skip-ssl
gbase> status
客户端指定非SSL(--skip-ssl),连接成功,为普通连接(Not in use)

$ gccli -h192.168.1.162 -ugbasessl -Dtestdb01 -p 
gbase> status;
客户端不指定,连接成功,为SSL

$ gccli -h192.168.1.162 -ugbasessl -Dtestdb01 -p --ssl
gbase> status;
客户端指定SSL(--ssl),连接成功,为SSL。
1)客户端指定 --ssl 但如果客户端配置未配置 ssl-cert、ssl-key 参数时,也能连接成功,为非SSL连接。
2)ssl-ca:非必须参数,如果不校验CA证书的话,不需要配置;

如果 gccli 客户端配置文件(gbase_8a_gcluster.cnf)未配置对应参数,也可以直接在 gccli 命令行指定 ssl 参数:
$ gccli -h192.168.1.162 -ugbase -Dtestdb01 -p --ssl  --ssl-cert=/opt/gbase8a/gccli/ssl/client-cert.pem  --ssl-key=/opt/gbase8a/gccli/ssl/client-key.pem 
$ gccli -h192.168.1.162 -ugbasessl -Dtestdb01 -p --ssl  --ssl-cert=/opt/gbase8a/gccli/ssl/client-cert.pem  --ssl-key=/opt/gbase8a/gccli/ssl/client-key.pem 

如果要校验CA证书,则指定 --ssl-ca CA证书文件路径(非必须):
$ gccli -h192.168.1.162 -ugbase -Dtestdb01 -p --ssl  --ssl-cert=/opt/gbase8a/gccli/ssl/client-cert.pem  --ssl-key=/opt/gbase8a/gccli/ssl/client-key.pem  --ssl-ca=/opt/gbase8a/gccli/ssl/ca-cert.pem
$ gccli -h192.168.1.162 -ugbasessl -Dtestdb01 -p --ssl  --ssl-cert=/opt/gbase8a/gccli/ssl/client-cert.pem  --ssl-key=/opt/gbase8a/gccli/ssl/client-key.pem  --ssl-ca=/opt/gbase8a/gccli/ssl/ca-cert.pem

jdbc 使用 ssl 加密连接传输数据
如果数据库的客户端应用(client)使用 jdbc 方式使用 ssl 加密连接方式,则应用客户端的配置参考如下:
如果使用 jdbc 进行 ssl 数据传输,前提也是必须 server 支持 ssl,必须先开启 server 端的 ssl 功能(开启配置详情可参考上面的 《1. 生成 SSL 连接证书》和《2. server 配置》章节)。

配置操作的命令集如下:

因为前面我配置过了,所以下面的1)和2)步骤我直接跳过,直接从步骤3)开始

1)生成 ssl 文件(直接在 linux 下执行即可)

生成 server 证书:
$ mkdir -p /opt/gbase8a/ssl
$ cd /opt/gbase8a/ssl
$ openssl genrsa 2048 > ca-key.pem  # CA 私钥
$ openssl req -sha1 -new -x509 -nodes -days 3650 -key ca-key.pem -out ca-cert.pem  # CA 证书。
注意:CA私钥和CA证书生成的两步也可以合并成一步操作:openssl req -sha1 -new -x509 -nodes -days 3650 -keyout ca-key.pem > ca-cert.pem 来代替
$ openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-req.pem  # 服务器私钥
$ openssl rsa -in server-key.pem -out server-key.pem  # 转为 RSA 格式,文件名也可以命名为:server-key.rsa
$ openssl x509 -sha1 -req -in server-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem  # 服务器证书
$ openssl verify -CAfile ca-cert.pem server-cert.pem  # 验证

生成 client 证书:
$ openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -out client-req.pem  # 客户端私钥
$ openssl rsa -in client-key.pem -out client-key.pem  # 转为 RSA 格式,文件名也可以命名为:client-key.rsa
$ openssl x509 -sha1 -req -in client-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem  # 客户端证书
$ openssl verify -CAfile ca-cert.pem client-cert.pem # 验证


ssl 证书相关查看命令:
openssl rsa -in server-key.pem -text          #查看证书私钥文件中的私钥和公钥信息
openssl x509 -in server-cert.pem -noout -text #查看证书详细信息


2)server 配置开启 ssl 功能:
vi $GCLUSTER_BASE/config/gbase_8a_gcluster.cnf

# 在 [gbased] 下配置 ssl 相关文件的路径
# server cfg for ssl
ssl-ca=/opt/gbase8a/ssl/ca-cert.pem
ssl-cert=/opt/gbase8a/ssl/server-cert.pem
ssl-key=/opt/gbase8a/ssl/server-key.pem


3)server 集群服务重启:
gcluster_services all restart

4)查看服务器SSL配置:
$ gccli -ugbase -p
gbase> show variables like '%SSL%';


经过前面三步集群已经开启ssl功能,针对jdbc按照如下使用步骤:

1) 生成jdbc连接用密钥(根据 ca-cert.pem 生成 truststore)
# su - frank
$ mkdir -p /home/frank/demo/ssl-certs/
$ cd /home/frank/demo/ssl-certs/
$ cp /home/frank/gccli/ssl/ca-cert.pem ./
$ cp /home/frank/gccli/ssl/client-cert.pem ./
$ keytool -import -alias GBaseCACert -file ca-cert.pem -keystore truststore
说明: ca-cert.pem 为服务器端生成 ssl 文件时生成的文件,执行该步骤后会提示输入认证密码,比如输入123456(jdbc连接会用到), Trust this certificate? [no]:  yes 


2)把 gbase Client 证书转换成DER格式:
$ openssl x509 -outform DER -in client-cert.pem -out client.cert

3)根据 client.cert 文件生成客户端 keystore 文件:
$ keytool -import -alias GBaseClientCertificate -file client.cert -keystore keystore 
说明: client-cert.pem 为生成 ssl 文件时生成的文件,执行该步骤后会提示输入认证密码,比如输入123456(jdbc连接会用到),Trust this certificate? [no]:  yes 


4)上述步骤会生成两个文件 truststore, keystore,将这两个文件拷贝到 jdbc 可以访问的路径下(例如:/home/frank/demo/ssl-certs/),我直接在该demo可访问的目录下生成的,无需再拷贝了

5) 参考下面方式编写连接测试代码(参考官方的《GBase 8a 程序员手册JDBC篇.pdf》中的ssl jdbc连接的介绍编码测试):

Main.java:

public class Main {public static void main(String args[]) {String str = "=== dbconnector in ===";System.out.println(CommonUtil.getMethodName() + str);System.out.println(CommonUtil.getMethodName() + "====================No SSL");GBase8aClient.connectTest();System.out.println(CommonUtil.getMethodName() + "====================SSL01");GBase8aClient.connectTestSSL01();System.out.println(CommonUtil.getMethodName() + "====================SSL02");GBase8aClient.connectTestSSL02();System.out.println(CommonUtil.getMethodName() + "====================SSL03");GBase8aClient.connectTestSSL03();System.out.println(CommonUtil.getMethodName() + "====================SSL04");GBase8aClient.connectTestSSL04();System.out.println(CommonUtil.getMethodName() + "====================SSL05");GBase8aClient.connectTestSSL05();System.out.println(CommonUtil.getMethodName() + "====================SSL06");GBase8aClient.connectTestSSL06();}
}

GBase8aClient.java:

public class GBase8aClient {static String user = "gbase";
//    static String user = "gbasessl";static String pwd = "1q2w3e";static String trustStorePath = System.getProperty("user.dir") + "/ssl-certs/truststore";static String keyStorePath = System.getProperty("user.dir") + "/ssl-certs/keystore";public static void printSysProperties() {System.out.println(CommonUtil.getMethodNameParent() + "keyStore:" + System.getProperty("javax.net.ssl.keyStore"));System.out.println(CommonUtil.getMethodNameParent() + "keyStorePassword:" + System.getProperty("javax.net.ssl.keyStorePassword"));System.out.println(CommonUtil.getMethodNameParent() + "trustStore:" + System.getProperty("javax.net.ssl.trustStore"));System.out.println(CommonUtil.getMethodNameParent() + "trustStorePassword:" + System.getProperty("javax.net.ssl.trustStorePassword"));}public static void setSysProperties(String target) {if ("keyStore".equalsIgnoreCase(target) || "all".equalsIgnoreCase(target)) {System.setProperty("javax.net.ssl.keyStore", keyStorePath);System.setProperty("javax.net.ssl.keyStorePassword", "123456");}if ("trustSotre".equalsIgnoreCase(target) || "all".equalsIgnoreCase(target)) {System.setProperty("javax.net.ssl.trustStore", trustStorePath);System.setProperty("javax.net.ssl.trustStorePassword", "123456");}}public static void removeSysProperties() {System.getProperties().remove("javax.net.ssl.keyStore");System.getProperties().remove("javax.net.ssl.keyStorePassword");System.getProperties().remove("javax.net.ssl.trustStore");System.getProperties().remove("javax.net.ssl.trustStorePassword");}public static void connectTest() {// 不设置 useSSL & requireSSL,使用非SSL连接String url = "jdbc:gbase://192.168.1.162:5258/testdb01";Connection conn = null;try {Class.forName("com.gbase.jdbc.Driver");conn = DriverManager.getConnection(url, user, pwd);Statement st = conn.createStatement();ResultSet rs = st.executeQuery("show status like '%SSL%'");while (rs.next()) {// 仅打印 Ssl_cipher, Ssl_cipher_list, Ssl_verify_depth, Ssl_verify_mode, Ssl_versionif (rs.getString(1).startsWith("Ssl_cipher") ||rs.getString(1).startsWith("Ssl_ver")) {System.out.println(rs.getString(1) + "-----"+ rs.getString(2).substring(0,min(50,rs.getString(2).length())));}}} catch (ClassNotFoundException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: ClassNotFound!");} catch (SQLException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: conn failed!" + e.getMessage());e.printStackTrace();} finally {if (null != conn) {try {conn.close();} catch (SQLException e) {}}}}public static void connectTestSSL01() {// 设置 useSSL & requireSSL,也设置 keystore & truststoreString url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true";setSysProperties("all");printSysProperties();Connection conn = null;try {Class.forName("com.gbase.jdbc.Driver");conn = DriverManager.getConnection(url, user, pwd);Statement st = conn.createStatement();ResultSet rs = st.executeQuery("show status like '%SSL%'");while (rs.next()) {// 仅打印 Ssl_cipher, Ssl_cipher_list, Ssl_verify_depth, Ssl_verify_mode, Ssl_versionif (rs.getString(1).startsWith("Ssl_cipher") ||rs.getString(1).startsWith("Ssl_ver")) {System.out.println(rs.getString(1) + "-----"+ rs.getString(2).substring(0,min(50,rs.getString(2).length())));}}} catch (ClassNotFoundException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: ClassNotFound!");} catch (SQLException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: conn failed!" + e.getMessage());e.printStackTrace();} finally {removeSysProperties();if (null != conn) {try {conn.close();} catch (SQLException e) {}}}}public static void connectTestSSL02() {// 设置 useSSL & requireSSL,设置 keystore,不设置 truststoreString url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true";setSysProperties("keyStore");printSysProperties();Connection conn = null;try {Class.forName("com.gbase.jdbc.Driver");conn = DriverManager.getConnection(url, user, pwd);Statement st = conn.createStatement();ResultSet rs = st.executeQuery("show status like '%SSL%'");while (rs.next()) {// 仅打印 Ssl_cipher, Ssl_cipher_list, Ssl_verify_depth, Ssl_verify_mode, Ssl_versionif (rs.getString(1).startsWith("Ssl_cipher") ||rs.getString(1).startsWith("Ssl_ver")) {System.out.println(rs.getString(1) + "-----"+ rs.getString(2).substring(0,min(50,rs.getString(2).length())));}}} catch (ClassNotFoundException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: ClassNotFound!");} catch (SQLException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: conn failed!" + e.getMessage());e.printStackTrace();} finally {removeSysProperties();if (null != conn) {try {conn.close();} catch (SQLException e) {}}}}public static void connectTestSSL03() {// 设置 useSSL & requireSSL,不设置 keystore & truststoreString url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true";printSysProperties();Connection conn = null;try {Class.forName("com.gbase.jdbc.Driver");conn = DriverManager.getConnection(url, user, pwd);Statement st = conn.createStatement();ResultSet rs = st.executeQuery("show status like '%SSL%'");while (rs.next()) {// 仅打印 Ssl_cipher, Ssl_cipher_list, Ssl_verify_depth, Ssl_verify_mode, Ssl_versionif (rs.getString(1).startsWith("Ssl_cipher") ||rs.getString(1).startsWith("Ssl_ver")) {System.out.println(rs.getString(1) + "-----"+ rs.getString(2).substring(0,min(50,rs.getString(2).length())));}}} catch (ClassNotFoundException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: ClassNotFound!");} catch (SQLException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: conn failed!" + e.getMessage());e.printStackTrace();} finally {if (null != conn) {try {conn.close();} catch (SQLException e) {}}}}public static void connectTestSSL04() {// 设置 useSSL & requireSSL,不设置 keystore & truststore// 暂未找到服务端模式的设置,尝试客户端设置校验模式:// 1)尝试设置 sslmode: disable | allow | prefer | require | verify-ca | verify-full,gbase8a 驱动不支持设置// 2)尝试设置 verifyServerCertificate = true// GBase官方手册没有找到 sslmode 和 verifyServerCertificate 的介绍,这个测试纯属尝试测试String url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true&verifyServerCertificate=true";printSysProperties();Connection conn = null;try {Class.forName("com.gbase.jdbc.Driver");conn = DriverManager.getConnection(url, user, pwd);Statement st = conn.createStatement();ResultSet rs = st.executeQuery("show status like '%SSL%'");while (rs.next()) {// 仅打印 Ssl_cipher, Ssl_cipher_list, Ssl_verify_depth, Ssl_verify_mode, Ssl_versionif (rs.getString(1).startsWith("Ssl_cipher") ||rs.getString(1).startsWith("Ssl_ver")) {System.out.println(rs.getString(1) + "-----"+ rs.getString(2).substring(0,min(50,rs.getString(2).length())));}}} catch (ClassNotFoundException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: ClassNotFound!");} catch (SQLException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: conn failed!" + e.getMessage());e.printStackTrace();} finally {if (null != conn) {try {conn.close();} catch (SQLException e) {}}}}public static void connectTestSSL05() {String url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true&verifyServerCertificate=true";setSysProperties("all");printSysProperties();Connection conn = null;try {Class.forName("com.gbase.jdbc.Driver");conn = DriverManager.getConnection(url, user, pwd);Statement st = conn.createStatement();ResultSet rs = st.executeQuery("show status like '%SSL%'");while (rs.next()) {// 仅打印 Ssl_cipher, Ssl_cipher_list, Ssl_verify_depth, Ssl_verify_mode, Ssl_versionif (rs.getString(1).startsWith("Ssl_cipher") ||rs.getString(1).startsWith("Ssl_ver")) {System.out.println(rs.getString(1) + "-----"+ rs.getString(2).substring(0,min(50,rs.getString(2).length())));}}} catch (ClassNotFoundException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: ClassNotFound!");} catch (SQLException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: conn failed!" + e.getMessage());e.printStackTrace();} finally {removeSysProperties();if (null != conn) {try {conn.close();} catch (SQLException e) {}}}}public static void connectTestSSL06() {// 测试失败:执行报错 KeyManagerFactoryImpl is not initializedString url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true&verifyServerCertificate=false&clientCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/keystore&clientCertificateKeyStorePassword=123456";
//        String url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true&verifyServerCertificate=true&clientCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/keystore&clientCertificateKeyStorePassword=123456&trustCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/truststore&trustCertificateKeyStorePassword=123456";printSysProperties();Connection conn = null;try {Class.forName("com.gbase.jdbc.Driver");conn = DriverManager.getConnection(url, user, pwd);Statement st = conn.createStatement();ResultSet rs = st.executeQuery("show status like '%SSL%'");while (rs.next()) {// 仅打印 Ssl_cipher, Ssl_cipher_list, Ssl_verify_depth, Ssl_verify_mode, Ssl_versionif (rs.getString(1).startsWith("Ssl_cipher") ||rs.getString(1).startsWith("Ssl_ver")) {System.out.println(rs.getString(1) + "-----"+ rs.getString(2).substring(0,min(50,rs.getString(2).length())));}}} catch (ClassNotFoundException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: ClassNotFound!");} catch (SQLException e) {System.out.println(CommonUtil.getMethodName() + "ERROR: conn failed!" + e.getMessage());e.printStackTrace();} finally {if (null != conn) {try {conn.close();} catch (SQLException e) {}}}}
}

5)编译 jar 拷贝到 /home/frank/demo/ 执行程序连接数据库
可以对比看出,几种不同的连接方式 show status like '%SSL%' 显示的信息有区别SSL还是非SSL:

[frank@localhost demo]$ java -Xbootclasspath/a:gbase-connector-java-9.5.0.1-build1-bin.jar  -jar dbconnector-1.0-SNAPSHOT-shaded-with-dependencies.jar
[main:27] === dbconnector in ===
[main:29] ====================No SSL
Ssl_cipher-----
Ssl_cipher_list-----
Ssl_verify_depth-----0
Ssl_verify_mode-----0
Ssl_version-----
[main:31] ====================SSL01
[connectTestSSL01:100] keyStore:/home/frank/demo/ssl-certs/keystore
[connectTestSSL01:100] keyStorePassword:123456
[connectTestSSL01:100] trustStore:/home/frank/demo/ssl-certs/truststore
[connectTestSSL01:100] trustStorePassword:123456
Ssl_cipher-----AES256-SHA
Ssl_cipher_list-----ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM
Ssl_verify_depth-----18446744073709551615
Ssl_verify_mode-----5
Ssl_version-----TLSv1
[main:33] ====================SSL02
[connectTestSSL02:137] keyStore:/home/frank/demo/ssl-certs/keystore
[connectTestSSL02:137] keyStorePassword:123456
[connectTestSSL02:137] trustStore:null
[connectTestSSL02:137] trustStorePassword:null
Ssl_cipher-----AES256-SHA
Ssl_cipher_list-----ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM
Ssl_verify_depth-----18446744073709551615
Ssl_verify_mode-----5
Ssl_version-----TLSv1
[main:35] ====================SSL03
[connectTestSSL03:173] keyStore:null
[connectTestSSL03:173] keyStorePassword:null
[connectTestSSL03:173] trustStore:null
[connectTestSSL03:173] trustStorePassword:null
Ssl_cipher-----AES256-SHA
Ssl_cipher_list-----ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM
Ssl_verify_depth-----18446744073709551615
Ssl_verify_mode-----5
Ssl_version-----TLSv1
[main:37] ====================SSL04
[connectTestSSL04:212] keyStore:null
[connectTestSSL04:212] keyStorePassword:null
[connectTestSSL04:212] trustStore:null
[connectTestSSL04:212] trustStorePassword:null
Ssl_cipher-----AES256-SHA
Ssl_cipher_list-----ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM
Ssl_verify_depth-----18446744073709551615
Ssl_verify_mode-----5
Ssl_version-----TLSv1
[main:39] ====================SSL05
[connectTestSSL05:247] keyStore:/home/frank/demo/ssl-certs/keystore
[connectTestSSL05:247] keyStorePassword:123456
[connectTestSSL05:247] trustStore:/home/frank/demo/ssl-certs/truststore
[connectTestSSL05:247] trustStorePassword:123456
Ssl_cipher-----AES256-SHA
Ssl_cipher_list-----ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM
Ssl_verify_depth-----18446744073709551615
Ssl_verify_mode-----5
Ssl_version-----TLSv1
[main:41] ====================SSL06
[connectTestSSL06:284] keyStore:null
[connectTestSSL06:284] keyStorePassword:null
[connectTestSSL06:284] trustStore:null
[connectTestSSL06:284] trustStorePassword:null
[connectTestSSL06:303] ERROR: conn failed!Could not create connection to database server.
com.gbase.jdbc.exceptions.jdbc4.GBaseNonTransientConnectionException: Could not create connection to database server.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at com.gbase.jdbc.Util.handleNewInstance(Util.java:422)
        at com.gbase.jdbc.Util.getInstance(Util.java:397)
        at com.gbase.jdbc.SQLError.createSQLException(SQLError.java:1024)
        at com.gbase.jdbc.SQLError.createSQLException(SQLError.java:998)
        at com.gbase.jdbc.SQLError.createSQLException(SQLError.java:993)
        at com.gbase.jdbc.SQLError.createSQLException(SQLError.java:935)
        at com.gbase.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2498)
        at com.gbase.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2247)
        at com.gbase.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:791)
        at com.gbase.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:49)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at com.gbase.jdbc.Util.handleNewInstance(Util.java:422)
        at com.gbase.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:375)
        at com.gbase.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:440)
        at java.sql.DriverManager.getConnection(DriverManager.java:664)
        at java.sql.DriverManager.getConnection(DriverManager.java:247)
        at com.dtdream.qftools.dbconnector.GBase8aClient.connectTestSSL06(GBase8aClient.java:289)
        at com.dtdream.qftools.dbconnector.Main.main(Main.java:42)
Caused by: java.lang.IllegalStateException: KeyManagerFactoryImpl is not initialized
        at sun.security.ssl.KeyManagerFactoryImpl.engineGetKeyManagers(KeyManagerFactoryImpl.java:51)
        at javax.net.ssl.KeyManagerFactory.getKeyManagers(KeyManagerFactory.java:289)
        at com.gbase.jdbc.ExportControlled.getSSLSocketFactoryDefaultOrConfigured(ExportControlled.java:256)
        at com.gbase.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:83)
        at com.gbase.jdbc.GBaseIO.negotiateSSLConnection(GBaseIO.java:4993)
        at com.gbase.jdbc.GBaseIO.doHandshake(GBaseIO.java:1381)
        at com.gbase.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2448)
        ... 14 more
[frank@localhost demo]$ 

另外,针对 GBase8a jdbc 连接,尝试了一下如果连接时指定 sslmode 参数(sslmode = disable | allow | prefer | require | verify-ca | verify-full),发现驱动不支持,会报下面错误信息:
[connectTestSSL04:236] ERROR: conn failed!driver not support property sslmode.
貌似客户端 jdbc 无法设置 sslmode,只能系统默认。


关于 useSSL 和 requireSSL 参数说明:
useSSL:是否建立SSL连接;
requireSSL:true代表如果服务端不支持SSL连接则失败,如果不指定该参数则默认为false、即如果服务端不支持SSL连接则会协商使用普通(非SSL)方式连接;

==============================

附录:

1)JDBC SSL 连接数据库时使用 keystore 的几种方式:

方式1:Java命令行参数设置:
-Djavax.net.ssl.keyStore=/home/frank/demo/ssl-certs/keystore
-Djavax.net.ssl.keyStorePassword=123456
如果双向认证设置 truststore :
-Djavax.net.ssl.trustStore=/home/frank/demo/ssl-certs/truststore
-Djavax.net.ssl.trustStorePassword=123456

如:
export JAVA_OPTS="-Djavax.net.ssl.keyStore=/home/frank/demo/ssl-certs/keystore -Djavax.net.ssl.keyStorePassword=123456 -Djavax.net.ssl.trustStore=/home/frank/demo/ssl-certs/truststore -Djavax.net.ssl.trustStorePassword=123456"
或直接指定参数执行java命令:
java -Djavax.net.ssl.keyStore=/home/frank/demo/ssl-certs/keystore -Djavax.net.ssl.keyStorePassword=123456 ......


方式2:直接在客户端代码中使用 System.setProperty() 设置:
System.setProperty("javax.net.ssl.keyStore", "/home/frank/demo/ssl-certs/keystore"); 
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
如果双向认证设置 truststore :
System.setProperty("javax.net.ssl.trustStore", "/home/frank/demo/ssl-certs/truststore"); 
System.setProperty("javax.net.ssl.trustStorePassword", "123456"); 


方式3:通过 Connector/J 连接属性设置:
clientCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/keystore
clientCertificateKeyStorePassword=123456
如果双向认证设置 truststore :
trustCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/truststore
trustCertificateKeyStorePassword=123456


方式4:JDBC 连接参数拼接方式设置:
String url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true&verifyServerCertificate=false&clientCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/keystore&clientCertificateKeyStorePassword=123456";

String url = "jdbc:gbase://192.168.1.162:5258/testdb01?useSSL=true&requireSSL=true&verifyServerCertificate=true&clientCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/keystore&clientCertificateKeyStorePassword=123456&trustCertificateKeyStoreUrl=file:/home/frank/demo/ssl-certs/truststore&trustCertificateKeyStorePassword=123456";

但有些情况下配置方式不生效,原因不明。


2)openssl主要参数:
req          大致有3个功能:生成证书请求文件、验证证书请求文件和创建根CA
-x509        说明生成自签名证书
-nodes       openssl req在自动创建私钥时,将总是加密该私钥文件,并提示输入加密的密码。可以使用"-nodes"选项禁止加密私钥文件
-days        指定所颁发的证书有效期(单位:天)
-new         新的请求
-newkey      直接指定私钥的算法和私钥长度,例如:-newkey rsa:2048 生成一个2048长度的RSA私钥文件、用于签发
             实际上,"-x509"选项和"-new"或"-newkey"配合使用时,可以不指定证书请求文件,它在自签署过程中将在内存中自动创建证书请求文件。"-newkey"和"-new"选项类似,只不过"-newkey"选项可以指定私钥的算法和长度
-keyout      指定私钥保存位置(含文件名)
-out         新的证书请求文件位置(含文件名)
-config      指定req的openssl配置文件,指定后将忽略所有的其他配置文件。如果不指定则默认使用 /etc/pki/tls/openssl.cnf 中 req段落的值
-text        text显示格式
-key         用于签名待生成的请求证书的私钥文件
-subj        设置CA证书subject


详细openssl参数请使用命令帮助查看 man openssl

3)JDBC连接驱动参数:

GBase8a官方手册上没有找到详细的JDBC驱动参数介绍,我参考了 MySQL JDBC 驱动参数进行配置和测试

MySQL 连接驱动所支持的 SSL 安全相关的参数如下:
JDBC连接驱动参数                     说明
sslMode                            默认值:preferred。此属性允许设置开启/关闭安全连接(SSL),或选择不同的安全级别: disabled | preferred | required 。
                                   服务器支持SSL的情况下,如果客户端未指定参数,默认效果为 preferred
                                   disabled: 使用普通连接(非SSL)
                                   preferred: 优先使用SSL连接、失败则回退使用普通连接
                                   required:  必须使用SSL连接、失败则失败 
useSSL                               默认值:false。是否建立SSL连接
requireSSL                           默认值:false。如果mysql服务器不支持SSL连接就会失败
clientCertificateKeyStoreType      默认值:JKS
clientCertificateKeyStoreUrl         keystore文件
clientCertificateKeyStorePassword     keystore密码
trustCertificateKeyStoreType       默认值:JKS
trustCertificateKeyStoreUrl           truststore文件
trustCertificateKeyStorePassword     truststore密码
tlsVersions                        TLS版本
verifyServerCertificate               默认值:false。是否需要检验mysql服务器的证书


4)系统用户表(user)的 ssl_type 属性与配置用户强制SSL连接

创建用户时指定 REQUIRE 或者创建以后单独通过 GRANT 修改:

1)CREATE 时指定强制SSL(并指定 ssl_type):CREATE USER 'test'@'%' REQUIRE X509;
2)GRANT 授权方式来修改SSL属性(ssl_type):示例如下

强制SSL 连接,默认ANY,此时也允许密码登录
gbase> grant all on testdb01.* to gbasessl require ssl;
gbase> select user,host,ssl_type from gbase.user;
+------------------------+-------------+----------+
| user                   | host        | ssl_type |
+------------------------+-------------+----------+
| root                   | %           |          |
| gbase                  | %           |          |
| gbasessl               | %           | ANY      |
+------------------------+-------------+----------+
gbase> flush privileges;

设置为X509以后,连接时在不指定ssl密钥时就不能登录了,必须指定ssl秘钥登录
gbase> grant all on testdb01.* to gbasessl require X509;
gbase> select user,host,ssl_type from gbase.user;
+------------------------+-------------+----------+
| user                   | host        | ssl_type |
+------------------------+-------------+----------+
| root                   | %           |          |
| gbase                  | %           |          |
| gbasessl               | %           | X509     |
+------------------------+-------------+----------+
gbase> flush privileges;
 

设置 X509以后,命令登录时必须指定证书和秘钥,但我本地的GBase8a上用 gccli 指定证书和秘钥登录未能成功:

gccli -h192.168.1.162 -ugbasessl -p -Dtestdb01 --ssl --ssl-cert=/home/frank/demo/ssl-certs/client-cert.pem -- --ssl-key=/home/frank/demo/ssl-certs/client-key.pem
最终还是改回了默认的ANY。

关闭该用户强制SSL连接
gbase> grant all on testdb01.* to gbasessl require none;
gbase> select user,host,ssl_type from gbase.user;
+------------------------+-------------+----------+
| user                   | host        | ssl_type |
+------------------------+-------------+----------+
| root                   | %           |          |
| gbase                  | %           |          |
| gbasessl               | %           |          |
+------------------------+-------------+----------+
gbase> FLUSH PRIVILEGES;
 

系统表 user 中的 ssl_type 参数:

MySQL是对应的 mysql.user 表, 而GBase8a对应的是 gbase.user 表。
ssl_type 参数支持的范围:enum('','ANY','X509','SPECIFIED')。

参数值说明:
空:标识该用户的强制SSL连接配置关闭;
ANY:代表该用户也可以使用密码登录、可以不指定秘钥(默认为该模式);
X509:代表该用户必须必须指定秘钥、禁止密码登录;
SPECIFIED:这个没有研究。

-- GBase
select user,host,ssl_type from gbase.user;

-- MySQL
select user,host,ssl_type from mysql.user;


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/124316.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络 期末复习方向

一&#xff0c;网络层 前三章我们解决了在具体物理网络&#xff0c;具体局域网上数据的传输过程&#xff0c;我们能实现在一个具体网络上把数据从A主机传到B主机&#xff0c;这件事情解决了。 引入问题&#xff1a;如果网络的局域网不考虑网络的扩展问题之后&#xff0c;我们…

【Leetcode】【简单】13. 罗马数字转整数

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/roman-to-integer/description/ …

在win10下,使用torchviz对深度学习网络模型进行可视化

目录 1. 安装 graphviz 和 torchviz 2.安装 graphviz.exe 3.实例测试 4.如果你的电脑还是无法画图&#xff0c;并且出现了下面的报错&#xff1a; 5.参考文章&#xff1a; 1. 安装 graphviz 和 torchviz 首先打开 Anaconda prompt 进入自己的 pytorch 环境(图中 pt 是我自…

servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header

目录 1、cookie和Session以及Header知识点 2、设置/获取 Cookie 3、设置/获取Session 4、设置/获取Header Cookie —— 客户端机制 Session —— 服务端机制 本篇博客主在用servlet和SpringBoot两种方式分别获取Session和Cookie&#xff0c;用来比较记忆与分析 1、cookie和…

MSQL系列(十二) Mysql实战-为什么索引要建立在被驱动表上

Mysql实战-left/right/inner join 使用详解 前面我们讲解了BTree的索引结构&#xff0c;也详细讲解下 left Join的底层驱动表 选择原理&#xff0c;那么今天我们来实战一下 left join&#xff0c;right join&#xff0c;inner join 等sql命令&#xff0c;看看到底如何用以及如…

Leetcode周赛369补题(3 / 3)

目录 1、找出数组的K-or值 - 位运算 模拟 2、数组的最小相等和 - 分情况讨论 3、使数组变美的最小增量运算数 - 动态规划dp 1、找出数组的K-or值 - 位运算 模拟 100111. 找出数组中的 K-or 值 思路&#xff1a; 根据范围&#xff0c;我们可以枚举0~30位&#xff0c;然后在…

【.net core】yisha框架bootstrapTreeTable组件实现行点击事件

YiSha.Web\YiSha.Admin.Web\wwwroot\lib\bootstrap.treetable\1.0\bootstrap-treetable.js文件中替换注册行点击选中事件代码 // 注册行点击选中事件var registerRowClickEvent function () {target.find("tbody").find("tr").unbind();target.find(&quo…

数据库软考知识

分布式数据库透明性 封锁 加上共享锁之后只能加共享锁&#xff0c;加上排他锁之后&#xff0c;啥锁都不能加。 分布式数据库特性 伪传递定理 SQL函数定义&#xff0c;有点冷 来了奥&#xff0c;更冷 存储过程 很重要&#xff0c;下午第二大题也是数据库

Java精品项目源码爱心捐赠平台网站(编号V65)

Java精品项目源码扶农助农平台建设系统(编号V64) 大家好&#xff0c;小辰今天给大家介绍一个爱心捐赠平台网站(编号V65)&#xff0c;演示视频公众号&#xff08;小辰哥的Java&#xff09;对号查询观看即可 文章目录 Java精品项目源码扶农助农平台建设系统(编号V64)难度指数&a…

【Apache Flink】实现有状态函数

文章目录 在RuntimeContext 中声明键值分区状态通过ListCheckPonitend 接口实现算子列表状态使用CheckpointedFunction接口接收检查点完成通知参考文档 在RuntimeContext 中声明键值分区状态 Flink为键值分区状态&#xff08;Keyed State&#xff09;提供了几种不同的原语&…

【洛谷 P1106】删数问题 题解(贪心+字符串)

删数问题 题目描述 键盘输入一个高精度的正整数 N N N&#xff08;不超过 250 250 250 位&#xff09;&#xff0c;去掉其中任意 k k k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N N N 和 k k k&#xff0c;寻找一种方案使得剩下的数字组成…

Arduino驱动ME007-ULA防水测距模组(超声波传感器)

目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 3.1、读取串口数据

css:如何通过不同的值,改变盒子的样式和字体颜色通过computed而不是v-if

在使用uniapp编写功能时&#xff0c;可以通过computed方法来实现根据num这个值也可以是后端传过来的值只要是number类型都可以。不同取值来修改盒子的背景颜色和字体颜色。首先&#xff0c;在data中定义一个num来存储当前的值&#xff0c;然后在computed中创建一个样式对象&…

如何在 uniapp 里面使用 pinia 数据持久化 (pinia-plugin-persistedstate)

想要在 uniapp 里面使用 pinia-plugin-persistedstate 会遇到的问题就是 uniapp里面没有浏览器里面的 sessionStorage localStorage 这些 api。 我们只需要替换掉 pinia-plugin-persistedstate 默认的储存 api 就可以了。使用 createPersistedState 重新创建一个实例, 把里面的…

Windows server服务器允许多用户远程的设置

在Windows Server上允许多用户同时进行远程桌面连接&#xff0c;您需要配置远程桌面服务以支持多用户并确保许可证和授权允许多用户连接。以下是在Windows Server上允许多用户远程桌面连接的步骤&#xff1a; 注意&#xff1a;这些步骤适用于 Windows Server 2012、Windows Ser…

开源B2B网站电子商务平台源码下载搭建 实现高效交易的桥梁

随着互联网的普及和电子商务的快速发展&#xff0c;B2B&#xff08;Business-to-Business&#xff09;网站电子商务平台在商业领域中发挥着越来越重要的作用。通过开源B2B网站电子商务平台源码搭建&#xff0c;企业可以构建自己的电子商务平台&#xff0c;实现高效交易的桥梁。…

Oracle修改带数据的字段类型

insert into TNW_FUND_SELORG(TFDINFOID,TSOINFOID) select TFD_INFO_ID,TSO_INFO_ID from TFD_SEL_FUNDLINK_TO_OLDFUNDWEB_DB /*修改原字段名*/ ALTER TABLE 表名 RENAME COLUMN 字段名 TO 字段名1; /*添加一个和原字段同名的字段*/ ALTER TABLE 表名 ADD 字段名 VARCHAR…

轻量级 IDE 文本编辑器 Geany 发布 2.0

Geany 是功能强大、稳定、轻量的开发者专用文本编辑器&#xff0c;支持 Linux、Windows 和 macOS&#xff0c;内置支持 50 多种编程语言。 2005 年Geany 发布首个版本 0.1。上周四刚好是 Geany 诞生 18 周年纪念日&#xff0c;官方发布了 2.0 正式版以表庆祝。 下载地址&#…

骨传导耳机优缺点是什么,这几点骨感耳机的利与弊一定得知道!

随着近几年骨感耳机的风头逐渐兴起&#xff0c;骨感耳机受到了不少人的关注&#xff0c;并且存在很多人对于骨感耳机的利与弊还存在着一定的盲点&#xff0c;下面让我来给大家讲解一下。 骨感耳机的利&#xff1a; 1、不入耳的设计对耳道的损伤更小 骨感耳机采用一种独特的声…

好用工具分享 | tmux 终端会话分离工具

目录 1 tmux的安装 2 tmux的基本操作 2.1 启动与退出 2.2 分离会话 2.3 查看会话 2.4 重接会话 2.5 杀死会话 2.6 切换会话 tmux是一个 terminal multiplexer&#xff08;终端复用器&#xff09;&#xff0c;它可以启动一系列终端会话。 我们使用命令行时&#xff0c;…