当前位置: 首页 > news >正文

基于tomcat的https(ssl)双向认证

一、背景介绍

        某个供应商服务需要部署到海外,如果海外多个地区需要部署多个服务,最好能实现统一登录,这样可以减轻用户的使用负担(不用记录一堆密码)。由于安全问题(可能会泄露用户数据),海外服务不能直连公司sso服务端,因此需要其他的方案解决安全问题。最终的安全方案中需要用到SSL双向认证进行数据的传输和交互,并且只指定某些个别接口实现SSL双向认证。在此背景下,这篇文章介绍基于tomcat的SSL双向认证的简单实现。

二、SSL简单介绍

        SSL(Secure Sockets Layer 安全套接层)就是一种协议(规范),用于保障客户端和服务器端通信的安全,以免通信时传输的信息被窃取或者修改。

        1.怎样保障数据传输安全?

        客户端和服务器端在进行握手(客户端和服务器建立连接和交换参数的过程称之为握手)时会产生一个“对话密钥”(session key),用来加密接下来的数据传输,解密时也是用的这个“对话密钥”,而这个“对话密钥”只有客户端和服务器端知道。也就是说只要这个“对话密钥”不被破解,就能保证安全。

  2. 客户端证书和服务器端证书

        客户端证书和服务器端证书用于证明自己的身份,就好比每个人都有一张身份证,这种身份证是唯一的。一般来说,只要有服务器端的证书就可以了,但是有时需要客户端提供自己的证书,已证明其身份。

三、生成自签名的服务器端证书和导入服务器端信任证书库

        一般证书可以使用权威机构颁发的证书,如:veri sign,百度使用的就是veri sign颁发的证书,这样的权威证书机构是受信任的,但是这些机构颁发的证书往往是需要收费的,这样的证书也难得到。对于小型企业来说为了节约成本,常常使用自签名的证书。   

        接下来使用JDK keytool工具来签发证书,如果未安装JDK,请先安装JDK(本文使用的是JDK8)。本文所有的证书文件都放到/cert/test1(操作系统centos),您可以选择一个目录来存放。

        1.制作服务端密钥库

keytool -genkey -v -alias server -keyalg RSA 
-keystore /cert/test1/server.keystore -validity 36500 
-ext SAN=dns:test-ssl,ip:10.1.x.x 
-dname "CN=test,OU=test,O=test,L=hz,ST=hz,C=cn"

 注意:SAN填写的是域名,IP填写是服务端IP。SAN和IP是解决谷歌浏览器证书无效的关键。

        2.制作客户端密钥库

keytool -genkey -v -alias client -keyalg RSA -storetype PKCS12 
-keystore /cert/test1/client.p12 -dname "CN=test,OU=test,O=test,L=hz,ST=hz,C=cn"

        3.客户端证书导入服务端密钥库

        由于不能直接将p12导入,需要先从客户端密钥库导出证书,再将导出的证书导入服务端密钥库。   

keytool -export -alias client -keystore /cert/test1/client.p12 
-storetype PKCS12 -storepass 123456 -rfc -file /cert/test1/client.cer

keytool -import -v -file /cert/test1/client.cer -keystore /cert/test1/server.keystore

        4.导出服务端密钥库证书 

keytool -keystore /cert/test1/server.keystore -export -alias server -file /cert/test1/server.cer

        5.配置tomcat 

        5.1配置server.xml

        找到conf目录下的server.xml文件,增加如下配置。

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"maxThreads="150" scheme="https" secure="true"clientAuth="true" sslProtocol="TLS"keystoreFile="/cert/test1/server.keystore" keystorePass="123456"truststoreFile ="/cert/test1/server.keystore" truststorePass="123456"
/>

        说明:
  • clientAuth为true表示开启SSL双向认证
  • keystoreFile指定服务器端的证书位置
  •  truststoreFile指定服务器端信任证书库
         5.2配置web.xml

        找到conf目录下的server.xml文件,增加如下配置。

<security-constraint><web-resource-collection><web-resource-name>SSL</web-resource-name><url-pattern>/ssl_test/*</url-pattern></web-resource-collection><user-data-constraint><description>SSL required</description><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint>
</security-constraint>

        说明:
  • 如果不加入这个配置,那么所有访问的地址都必须要使用SSL才能访问,有时我们可能只需要通过某个或者某些SSL地址获取客户端证书来认证用户身份,认证成功后不需要使用SSL来进行访问(可以配置多个security-constraint)
  • url-pattern:指定需要SSL才能进行访问的地址(/ssl_test/*)
  • transport-guarantee:合法值为NONE、 INTEGRAL或CONFIDENTIAL,transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上(并且在未来的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL
  • 创建SSLServlet获取客户端证书

        6.编写用来获取客户端证书的filter及测试接口类

        客户端证书验证拦截器(拦截路径:/ssl_test/*)
package com.example.demo;import java.io.IOException;
import java.security.cert.X509Certificate;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;/*** description:MyFilter** @author: lgq* @create: 2024-02-02 10:55*/@WebFilter(urlPatterns = "/ssl_test/*")
public class MyFilter implements Filter {private static final String REQUEST_ATTR_CERT = "javax.servlet.request.X509Certificate";private static final String SCHEME_HTTPS = "https";/*** web应用启动时,web服务器将创建Filter的实例对象,并调用init方法,读取web.xml的配置,完成对象的初始化功能,* 从而为后续的用户请求做好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次,开发人员通过init的参数,* 可或得代表当前filter配置信息的FilterConfig对象)* @param filterConfig* @throws ServletException*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}/*** 这个方法完成实际的过滤操作,当客户请求访问与过滤器相关联的URL的时候,Servlet过滤器将先执行doFilter方法,FilterChain参数用于访问后续过滤器* @param request* @param response* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)throws IOException, ServletException {X509Certificate[] certs = (X509Certificate[]) request.getAttribute(REQUEST_ATTR_CERT);if (certs != null) {int count = certs.length;System.out.println("共检测到[" + count + "]个客户端证书");for (int i = 0; i < count; i++) {X509Certificate cert = certs[i];System.out.println("客户端证书 [" + cert.getSubjectDN() + "]: ");System.out.println("证书是否有效:" + (verifyCertificate(cert) ? "是" : "否"));System.out.println("证书详细信息:\r" + cert.toString());}filterChain.doFilter(request, response);} else {if (SCHEME_HTTPS.equalsIgnoreCase(request.getScheme())) {System.out.println("这是一个HTTPS请求,但是没有可用的客户端证书");} else {System.out.println("这不是一个HTTPS请求,因此无法获得客户端证书列表 ");}}System.out.println("我是过滤器,我进来了");}/*** filter创建后会保存在内存中,当web应用移除或者服务器停止时才销毁,该方法在Filter的生命周期中仅执行一次,在这个方法中,可以释放过滤器使用的资源*/@Overridepublic void destroy() {}/**** 校验证书是否过期*** @param certificate* @return*/private boolean verifyCertificate(X509Certificate certificate) {boolean valid = true;try {certificate.checkValidity();} catch (Exception e) {e.printStackTrace();valid = false;}return valid;}
}
         启动类(服务部署到tomcat)
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;@SpringBootApplication
@ServletComponentScan
public class DemoApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(DemoApplication.class);}}
        pom依赖(打war包)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><name>demo</name><description>Demo project for Spring Boot</description><packaging>war</packaging><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><!--spring boot tomcat(默认可以不用配置,但当需要把当前web应用布置到外部servlet容器时就需要配置,并将scope配置为provided)--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency></dependencies><build><finalName>test</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>2.1.1</version><configuration><failOnMissingWebXml>false</failOnMissingWebXml></configuration></plugin></plugins></build></project>
        tomcat下服务目录(工程路径/test)

        启动服务命令

        客户端ssl证书认证接口
package com.example.demo;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** description:SSLTestController ** @author: lgq* @create: 2024-01-25 10:42*/
@RestController
@RequestMapping("/ssl_test")
public class SSLTestController {@GetMapping("/hello")public String auth() {return "Hello, I am the server! Your client's SSL certificate has been authenticated!";}
}
        不需要认证客户端证书的接口
package com.example.demo;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** description:NoSSLTestController** @author: lgq* @create: 2024-01-25 10:42*/
@RestController
@RequestMapping("/no_ssl_test")
public class NoSSLTestController {@GetMapping("/hello")public String auth() {return "Hello, I am the server!";}
}

        7.测试

        7.1 浏览器访问测试
        7.1.1ssl双向认证测试

        用浏览器访问http://10.1.x.x:8080/test/ssl_test/hello        

        细心的读者可能发现链接已经跳转到了  https://10.1.x.x:8443/test/ssl_test/hello,这是由于这个地址被设置为需要SSL才能访问,所以跳转到了这个地址。访问时页面提示如下:

        为了不出现这样的警告信息,我们可以导入服务器端证书到客户端,双击服务端证书

        选择当前用户 

        将证书放入可信任的根证书列表 ,随后安装成功

        再次访问: http://10.1.x.x:8080/test/ssl_test/hello,出现如下错误

        由于我们访问的接口是双向认证,所以也需要客户端的证书,我们接下来导入客户端证书

        自动选择证书存储 

        输入证书密钥,随即安装成功 

        第三次访问: http://10.1.x.x:8080/test/ssl_test/hello,结果如下所示

        需要选择客户端证书

        输出结果如下 

        tomcat 日志如下,(证书是否有效:是)表示客户端证书已经通过服务端验证

        7.1.2 不验证客户端证书

        访问地址http://10.1.x.x:8080/test/no_ssl_test/hello​​​​​​, 发现没有跳转到8443端口,正常返回内容如下

        7.2 测试java通过httpclient调用双向认证接口 
        1.增加apache httpclient依赖
 <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.10</version>
</dependency><!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.6</version>
</dependency>
        2.构建http请求类
package com.example.demo;/*** description:HttpsRequest** @author: lgq* @create: 2024-02-04 18:17*/import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Map;import javax.net.ssl.SSLContext;import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;public class HttpsRequest {//.p12文件路径private String filePath;//密码private String passWord;//外呼urlprivate String url;// 请求体private String body;//请求头private Map<String, String> header;//代理IPprivate String proxyIP;//代理端口private int proxyPort;private HttpsRequest(Builder builder) {this.filePath = builder.filePath;this.passWord = builder.passWord;this.url = builder.url;this.body = builder.body;this.header = builder.header;this.proxyIP = builder.proxyIP;this.proxyPort = builder.proxyPort;}public static class Builder {//.p12文件路径private String filePath;//密码private String passWord;//外呼urlprivate String url;// 请求体private String body;//请求头private Map<String, String> header = new HashMap<>();//代理IPprivate String proxyIP;//代理端口private int proxyPort;public Builder filePath(String filePath) {this.filePath = filePath;return this;}public Builder passWord(String passWord) {this.passWord = passWord;return this;}public Builder url(String url) {this.url = url;return this;}public Builder body(String body) {this.body = body;return this;}public Builder header(String key, String value) {this.header.put(key, value);return this;}public Builder proxy(String ip, int port) {this.proxyPort = port;this.proxyIP = ip;return this;}public HttpsRequest build() {return new HttpsRequest(this);}}public String doPost() {String rep = "";SSLContext sslcontext;try {KeyStore keyStore = KeyStore.getInstance("PKCS12");try (FileInputStream fileInputStream = new FileInputStream(filePath)) {keyStore.load(fileInputStream, passWord.toCharArray());sslcontext = SSLContexts.custom()//忽略掉对服务器端证书的校验//.loadTrustMaterial((TrustStrategy) (chain, authType) -> true)//加载服务端提供的truststore(如果服务器提供truststore的话就不用忽略对服务器端证书的校验了).loadTrustMaterial(new File("E:\\abc\\def\\server.jks"), "123456".toCharArray(),new TrustSelfSignedStrategy()).loadKeyMaterial(keyStore, passWord.toCharArray()).build();}SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext,new String[]{"TLSv1"},null,SSLConnectionSocketFactory.getDefaultHostnameVerifier());try (CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build()) {HttpPost httpPost = new HttpPost(url);StringEntity req = new StringEntity(body, "UTF-8");httpPost.setEntity(req);if (header != null) {header.entrySet().stream().forEach((h) -> {httpPost.addHeader(h.getKey(), h.getValue());});}RequestConfig config;if (!StringUtils.isEmpty(proxyIP) && !StringUtils.isEmpty(proxyPort)) {HttpHost proxy = new HttpHost(proxyIP, proxyPort);config = RequestConfig.custom().setProxy(proxy).setConnectionRequestTimeout(5000).setSocketTimeout(30000).setConnectTimeout(20000).build();} else {config = RequestConfig.custom().setConnectionRequestTimeout(5000).setSocketTimeout(30000).setConnectTimeout(20000).build();}//连接超时时间, 单位毫秒//requestConfigBuilder.setConnectTimeout(2000);//从池中获取连接超时时间//requestConfigBuilder.setConnectionRequestTimeout(500);//读超时时间(等待数据超时时间)//requestConfigBuilder.setSocketTimeout(2000);httpPost.setConfig(config);try (CloseableHttpResponse httpResponse = client.execute(httpPost)) {HttpEntity entity = httpResponse.getEntity();rep = EntityUtils.toString(entity);}}} catch (KeyStoreException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (CertificateException e) {e.printStackTrace();} catch (KeyManagementException e) {e.printStackTrace();} catch (UnrecoverableKeyException e) {e.printStackTrace();}return rep;}public String doGet() {String rep = "";SSLContext sslcontext;try {KeyStore keyStore = KeyStore.getInstance("PKCS12");try (FileInputStream fileInputStream = new FileInputStream(filePath)) {keyStore.load(fileInputStream, passWord.toCharArray());sslcontext = SSLContexts.custom()//忽略掉对服务器端证书的校验//.loadTrustMaterial((TrustStrategy) (chain, authType) -> true)//加载服务端提供的truststore(如果服务器提供truststore的话就不用忽略对服务器端证书的校验了).loadTrustMaterial(new File("E:\\abc\\def\\server.jks"), "123456".toCharArray(),new TrustSelfSignedStrategy()).loadKeyMaterial(keyStore, passWord.toCharArray()).build();}SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext,new String[]{"TLSv1.2"},null,SSLConnectionSocketFactory.getDefaultHostnameVerifier());try (CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build()) {HttpGet httpGet = new HttpGet(url);if (!ObjectUtils.isEmpty(header)) {header.entrySet().stream().forEach((h) -> {httpGet.addHeader(h.getKey(), h.getValue());});}RequestConfig config;if (!ObjectUtils.isEmpty(proxyIP) && !ObjectUtils.isEmpty(proxyPort)) {HttpHost proxy = new HttpHost(proxyIP, proxyPort);config = RequestConfig.custom().setProxy(proxy).setConnectionRequestTimeout(5000).setSocketTimeout(30000).setConnectTimeout(20000).build();} else {config = RequestConfig.custom().setConnectionRequestTimeout(5000).setSocketTimeout(30000).setConnectTimeout(20000).build();}//连接超时时间, 单位毫秒//requestConfigBuilder.setConnectTimeout(2000);//从池中获取连接超时时间//requestConfigBuilder.setConnectionRequestTimeout(500);//读超时时间(等待数据超时时间)//requestConfigBuilder.setSocketTimeout(2000);httpGet.setConfig(config);try (CloseableHttpResponse httpResponse = client.execute(httpGet)) {HttpEntity entity = httpResponse.getEntity();rep = EntityUtils.toString(entity);}}} catch (KeyStoreException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (CertificateException e) {e.printStackTrace();} catch (KeyManagementException e) {e.printStackTrace();} catch (UnrecoverableKeyException e) {e.printStackTrace();}return rep;}}
3.将服务端证书由 cer格式转为jks
keytool -import -alias server -file /cert/test1/server.cer -keystore /cert/test1/server.jks
 4.测试双向认证请求
package com.example.demo;/*** description:HttpsRequestTest** @author: lgq* @create: 2024-02-04 18:24*/
public class HttpsRequestTest {public static void main(String[] args) {String result = new HttpsRequest.Builder().filePath("E:\\abc\\def\\client.p12").passWord("123456").url("https://10.1.x.x:8443/test/ssl_test/hello").header("charset", "UTF-8")//头信息,多个头信息多次调用此方法即可.build().doGet();System.out.println(result);}
}

        输出结果

"C:\Program Files\Java\jdk1.8.0_101\bin\java.exe" -Dvisualvm.id=375771477320700 "-javaagent:E:\software-tools\JetBrains\IntelliJ IDEA 2020.3.3\lib\idea_rt.jar=55001:E:\software-tools\JetBrains\IntelliJ IDEA 2020.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_101\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar;D:\project\demo1\target\classes;D:\maven\repository\org\springframework\boot\spring-boot-starter-web\2.4.3\spring-boot-starter-web-2.4.3.jar;D:\maven\repository\org\springframework\boot\spring-boot-starter\2.4.3\spring-boot-starter-2.4.3.jar;D:\maven\repository\org\springframework\boot\spring-boot\2.4.3\spring-boot-2.4.3.jar;D:\maven\repository\org\springframework\boot\spring-boot-autoconfigure\2.4.3\spring-boot-autoconfigure-2.4.3.jar;D:\maven\repository\org\springframework\boot\spring-boot-starter-logging\2.4.3\spring-boot-starter-logging-2.4.3.jar;D:\maven\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\maven\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\maven\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\maven\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\maven\repository\org\springframework\spring-core\5.3.4\spring-core-5.3.4.jar;D:\maven\repository\org\springframework\spring-jcl\5.3.4\spring-jcl-5.3.4.jar;D:\maven\repository\org\yaml\snakeyaml\1.27\snakeyaml-1.27.jar;D:\maven\repository\org\springframework\boot\spring-boot-starter-json\2.4.3\spring-boot-starter-json-2.4.3.jar;D:\maven\repository\com\fasterxml\jackson\core\jackson-databind\2.11.4\jackson-databind-2.11.4.jar;D:\maven\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.4\jackson-annotations-2.11.4.jar;D:\maven\repository\com\fasterxml\jackson\core\jackson-core\2.11.4\jackson-core-2.11.4.jar;D:\maven\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.4\jackson-datatype-jdk8-2.11.4.jar;D:\maven\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.4\jackson-datatype-jsr310-2.11.4.jar;D:\maven\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.4\jackson-module-parameter-names-2.11.4.jar;D:\maven\repository\org\springframework\spring-web\5.3.4\spring-web-5.3.4.jar;D:\maven\repository\org\springframework\spring-beans\5.3.4\spring-beans-5.3.4.jar;D:\maven\repository\org\springframework\spring-webmvc\5.3.4\spring-webmvc-5.3.4.jar;D:\maven\repository\org\springframework\spring-aop\5.3.4\spring-aop-5.3.4.jar;D:\maven\repository\org\springframework\spring-context\5.3.4\spring-context-5.3.4.jar;D:\maven\repository\org\springframework\spring-expression\5.3.4\spring-expression-5.3.4.jar;D:\maven\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\repository\org\apache\httpcomponents\httpcore\4.4.10\httpcore-4.4.10.jar;D:\maven\repository\org\apache\httpcomponents\httpclient\4.5.6\httpclient-4.5.6.jar;D:\maven\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar" com.example.demo.HttpsRequestTest
18:55:06.389 [main] DEBUG org.apache.http.client.protocol.RequestAddCookies - CookieSpec selected: default
18:55:06.411 [main] DEBUG org.apache.http.client.protocol.RequestAuthCache - Auth cache not set in the context
18:55:06.413 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection request: [route: {s}->https://10.1.x.x:8443][total kept alive: 0; route allocated: 0 of 2; total allocated: 0 of 20]
18:55:06.429 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection leased: [id: 0][route: {s}->https://10.1.x.x:8443][total kept alive: 0; route allocated: 1 of 2; total allocated: 1 of 20]
18:55:06.431 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Opening connection {s}->https://10.1.x.x:8443
18:55:06.434 [main] DEBUG org.apache.http.impl.conn.DefaultHttpClientConnectionOperator - Connecting to /10.1.x.x:8443
18:55:06.434 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Connecting socket to /10.1.x.x:8443 with timeout 20000
18:55:06.491 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled protocols: [TLSv1.2]
18:55:06.491 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled cipher suites:[TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
18:55:06.491 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Starting handshake
18:55:06.598 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Secure session established
18:55:06.598 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory -  negotiated protocol: TLSv1.2
18:55:06.598 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory -  negotiated cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
18:55:06.598 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory -  peer principal: CN=test, OU=test, O=test, L=hz, ST=hz, C=cn
18:55:06.599 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory -  peer alternative names: [test-ssl, 10.1.x.x]
18:55:06.599 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory -  issuer principal: CN=test, OU=test, O=test, L=hz, ST=hz, C=cn
18:55:06.605 [main] DEBUG org.apache.http.impl.conn.DefaultHttpClientConnectionOperator - Connection established 10.26.54.125:55008<->10.1.x.x:8443
18:55:06.605 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: set socket timeout to 30000
18:55:06.606 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Executing request GET /test/ssl_test/hello HTTP/1.1
18:55:06.606 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Target auth state: UNCHALLENGED
18:55:06.607 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED
18:55:06.609 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> GET /test/ssl_test/hello HTTP/1.1
18:55:06.609 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> charset: UTF-8
18:55:06.609 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Host: 10.1.x.x:8443
18:55:06.610 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Connection: Keep-Alive
18:55:06.610 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.6 (Java/1.8.0_101)
18:55:06.610 [main] DEBUG org.apache.http.headers - http-outgoing-0 >> Accept-Encoding: gzip,deflate
18:55:06.610 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "GET /test/ssl_test/hello HTTP/1.1[\r][\n]"
18:55:06.610 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "charset: UTF-8[\r][\n]"
18:55:06.610 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Host: 10.1.x.x:8443[\r][\n]"
18:55:06.610 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
18:55:06.610 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.6 (Java/1.8.0_101)[\r][\n]"
18:55:06.610 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
18:55:06.610 [main] DEBUG org.apache.http.wire - http-outgoing-0 >> "[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 200 [\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Cache-Control: private[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Content-Type: text/plain;charset=UTF-8[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Content-Length: 77[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Date: Sun, 04 Feb 2024 10:55:07 GMT[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Keep-Alive: timeout=60[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Connection: keep-alive[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\r][\n]"
18:55:06.619 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Hello, I am the server! Your client's SSL certificate has been authenticated!"
18:55:06.624 [main] DEBUG org.apache.http.headers - http-outgoing-0 << HTTP/1.1 200 
18:55:06.624 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Cache-Control: private
18:55:06.624 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Type: text/plain;charset=UTF-8
18:55:06.624 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Length: 77
18:55:06.624 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Date: Sun, 04 Feb 2024 10:55:07 GMT
18:55:06.624 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Keep-Alive: timeout=60
18:55:06.624 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Connection: keep-alive
18:55:06.632 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Connection can be kept alive for 60000 MILLISECONDS
18:55:06.640 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection [id: 0][route: {s}->https://10.1.x.x:8443][state: CN=test, OU=test, O=test, L=hz, ST=hz, C=cn] can be kept alive for 60.0 seconds
18:55:06.640 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: set socket timeout to 0
18:55:06.640 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {s}->https://10.1.x.x:8443][state: CN=test, OU=test, O=test, L=hz, ST=hz, C=cn][total kept alive: 1; route allocated: 1 of 2; total allocated: 1 of 20]
18:55:06.641 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection manager is shutting down
18:55:06.641 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: Close connection
18:55:06.642 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection manager shut down
Hello, I am the server! Your client's SSL certificate has been authenticated!Process finished with exit code 0

        其中,输出内容:“Hello, I am the server! Your client's SSL certificate has been authenticated!”,表示客户端证书认证已经通过。需要注意的是,上面方法中,客户端证书使用的是p12格式,服务端证书使用jks格式。

相关文章:

基于tomcat的https(ssl)双向认证

一、背景介绍 某个供应商服务需要部署到海外&#xff0c;如果海外多个地区需要部署多个服务&#xff0c;最好能实现统一登录&#xff0c;这样可以减轻用户的使用负担&#xff08;不用记录一堆密码&#xff09;。由于安全问题&#xff08;可能会泄露用户数据&#xff09;&#x…...

【iOS ARKit】3D人体姿态估计实例

与2D人体姿态检测一样&#xff0c;在ARKit 中&#xff0c;我们不必关心底层的人体骨骼关节点检测算法&#xff0c;也不必自己去调用这些算法&#xff0c;在运行使用 ARBodyTrackingConfiguration 配置的 ARSession 之后&#xff0c;基于摄像头图像的3D人体姿态估计任务也会启动…...

ROS2 CMakeLists.txt 和 package.xml

这里记录一下ROS2中功能包package.xml和CMakeLists.txt的格式。以LIO-SAM的ROS2版本为例&#xff1a; 一&#xff1a;CMakeLists.txt cmake_minimum_required(VERSION 3.5) project(lio_sam)if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)set(CMAKE_BUILD_TYPE…...

代码献瑞,算力有礼!低代码开发工具PaddleX特色产线新春福利来啦

回望2023年&#xff0c;飞桨在开发套件能力基础上&#xff0c;充分结合大模型能力&#xff0c;正式在飞桨星河社区上线发布了低代码开发工具PaddleX&#xff0c;实现AI应用开发效果和效率的大幅提升。产品通过提供图形界面开发模式&#xff0c;将复杂的编程任务简化为简单易用的…...

C语言:操作符详解

创作不易&#xff0c;给个三连吧&#xff01;&#xff01; 一、算术操作符 C语言中为了方便计算&#xff0c;提供了算数操作符&#xff0c;分别是:,-,*,/,% 由于这些操作符都是有两个操作数&#xff08;位于操作符两边&#xff09;&#xff0c;所以这种操作符也叫做双目操作…...

Rust 初体验2

变量类型 Rust 语言的变量数据类型&#xff0c;主要包括整型、浮点型、字符、布尔型、元组、数组、字符串、枚举、结构体和可变变量等。 fn main() { // 整型 let integer: i32 100; println!("整型: {}", integer); // 浮点型 let floating_point: f64 3.1…...

vue-cil的watch函数详解

在Vue中&#xff0c;watch是一个非常有用的API&#xff0c;用于侦听一个响应式引用&#xff08;例如由ref创建&#xff09;或响应式对象&#xff08;由reactive创建&#xff09;的属性&#xff0c;并在值变化时执行回调函数。Vue 3的Composition API引入了这种侦听方式&#xf…...

堆排及时间复杂度分析

箴言: 初始阶段&#xff0c;不需要去纠结那一种更优美&#xff0c;非要找出那一种是最好的&#xff0c;其实能解决问题的就是好办法。 一&#xff0c;常见排序时间复杂度 冒泡快排归并堆排桶排时间O(n^2)O(nlogn)O(nlogn)O(nlogn)kn空间O(1)O(1)O(nlogn)O(1)kn 二&#xff…...

数据结构:双向链表

文章目录 1. 双向带头循环链表的结构2. 相关操作2.1 创建节点2.2 尾插2.3 头插2.4 打印2.5 尾删2.6 头删2.7 查找2.8 指定位置前/后插入2.9 删除指定位置的节点2.10 删除指定位置后的节点2.11 销毁链表 3.顺序表与链表区别 1. 双向带头循环链表的结构 与单链表不同的是&#xf…...

51单片机之数码管显示表白数字篇

朝菌不知晦朔 蟪蛄不知春秋 眼界决定境界 CSDN 请求进入专栏 是否进入《51单片机专栏》? 确定 目录 数码管的简介 数码管引脚定义 数码管的原理图 74HC245 代码实现 静态数码管的显示 动态数码管的显示 数码管实现表白画面 数码管的简介 L…...

代码随想录算法训练营DAY16 | 二叉树 (3)

一、LeetCode 104 二叉树的最大深度 题目链接&#xff1a;104.二叉树的最大深度https://leetcode.cn/problems/maximum-depth-of-binary-tree/ 思路&#xff1a;采用后序遍历递归求解。 class Solution {int ans 0;public int maxDepth(TreeNode root) {if(root null){retur…...

springboot(ssm大学生计算机基础网络教学系统 在线课程系统Java系统

springboot(ssm大学生计算机基础网络教学系统 在线课程系统Java系统 开发语言&#xff1a;Java 框架&#xff1a;springboot&#xff08;可改ssm&#xff09; vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mys…...

前端架构: 脚手架的开发流程和常用框架

脚手架的开发流程 脚手架的创建 $ npm init 脚手架的开发 分包 分包是指当我们一个脚手架比较复杂的时候&#xff0c;不可能把所有的js代码全部写在一个脚手架当中势必会把它建很多的不同的模块 package&#xff0c;通常我们会把它称之为一个分包的过程会和实际的这个项目一样…...

3.0 Hadoop 概念

本章着重介绍 Hadoop 中的概念和组成部分&#xff0c;属于理论章节。如果你比较着急可以跳过。但作者不建议跳过&#xff0c;因为它与后面的章节息息相关。 Hadoop 整体设计 Hadoop 框架是用于计算机集群大数据处理的框架&#xff0c;所以它必须是一个可以部署在多台计算机上…...

mysql 对于null字段排序处理

最近遇到一个需求 &#xff0c;需要对一个报表的多个字段进行多字段复杂条件排序 排序字段为NULL时 Mysql对于排序字段为NULL时&#xff0c;有自身默认的排序规则&#xff0c;默认是认为null 值 是无穷小 ELECT id,script_id,last_modified,live_count,next_show FROM virtua…...

NLP_语言模型的雏形 N-Gram 模型

文章目录 N-Gram 模型1.将给定的文本分割成连续的N个词的组合(N-Gram)2.统计每个N-Gram在文本中出现的次数&#xff0c;也就是词频3.为了得到一个词在给定上下文中出现的概率&#xff0c;我们可以利用条件概率公式计算。具体来讲&#xff0c;就是计算给定前N-1个词时&#xff0…...

mac电脑flutter环境配置,解决疑难问题

准备工作 首先搭建flutter的环境需要使用到flutter的sdk&#xff0c;可以直接跳去官网下载&#xff1a;Choose your first type of app - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter&#xff0c;下载时要注意你电脑所使用的芯片是Intel的还是苹果的芯片。 下载好的…...

C++ bool 布尔类型

在C 中 bool类型占用1个字节长度&#xff0c;bool 类型只有两个取值&#xff0c;true 和 false&#xff0c;true 表示“真”&#xff0c;false 表示“假”。 需要注意的C中使用cout 打印的时候是没有true 和 false 的 只有0和1 &#xff0c;这里0表示假&#xff0c;非0表示真 …...

DC-7靶机渗透详细流程

信息收集&#xff1a; 1.存活扫描&#xff1a; 由于靶机和kali都是nat的网卡&#xff0c;都在一个网段&#xff0c;我们用arp-scan会快一点&#xff1a; arp-scan arp-scan -I eth0 -l └─# arp-scan -I eth0 -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:dd:ee:6…...

提速MySQL:数据库性能加速策略全解析

提速MySQL&#xff1a;数据库性能加速策略全解析 引言理解MySQL性能指标监控和评估性能指标索引优化技巧索引优化实战案例 查询优化实战查询优化案例分析 存储引擎优化InnoDB vs MyISAM选择和优化存储引擎存储引擎优化实例 配置调整与系统优化配置调整系统优化优化实例 实战案例…...

Flink实战六_直播礼物统计

接上文&#xff1a;Flink实战五_状态机制 1、需求背景 现在网络直播平台非常火爆&#xff0c;在斗鱼这样的网络直播间&#xff0c;经常可以看到这样的总榜排名&#xff0c;体现了主播的人气值。 人气值计算规则&#xff1a;用户发送1条弹幕互动&#xff0c;赠送1个荧光棒免费…...

Compose | UI组件(十五) | Scaffold - 脚手架

文章目录 前言一、Scaffold脚手架简介二、Scaffold的主要组件三、如何使用Scaffold四、Compose中Scaffold脚手架的具体例子例子1&#xff1a;基本Scaffold布局例子2&#xff1a;带有Drawer的Scaffold布局例子3&#xff1a;带有Snackbar的Scaffold布局 总结 前言 Compose中的Sca…...

Vue-60、Vue技术router-link的replace属性

1、作用&#xff1a;控制路由跳转时操作浏览器历史记录的模式 2、浏览器的历史记录有两种写入方式&#xff1a;分别是push和replace,push是追加历史记录&#xff0c;replace是替换当前记录。路由跳转时候默认为push 3、如何开启replace模式&#xff1a; <router-link rep…...

Hive与Presto中的列转行区别

Hive与Presto列转行的区别 1、背景描述2、Hive/Spark列转行3、Presto列转行 1、背景描述 在处理数据时&#xff0c;我们经常会遇到一个字段存储多个值&#xff0c;这时需要把一行数据转换为多行数据&#xff0c;形成标准的结构化数据 例如&#xff0c;将下面的两列数据并列转换…...

探讨CSDN等级制度:博客等级、原力等级、创作者等级

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…...

2.8作业

sqlite3数据库操作接口详细整理&#xff0c;以及常用的数据库语句 头文件&#xff1a; #include <sqlite3.h> 编译时候要加上-lsqlite3 gcc a.c -lsqlite3 1&#xff09;sqlite3_open 打开一个数据库&#xff0c;如果数据库不存在&#xff0c;则创建一个数据库 2&am…...

机器学习中常用的性能度量—— ROC 和 AUC

什么是泛化能力&#xff1f; 通常我们用泛化能力来评判一个模型的好坏&#xff0c;通俗的说&#xff0c;泛化能力是指一个机器学期算法对新样本&#xff08;即模型没有见过的样本&#xff09;的举一反三的能力&#xff0c;也就是学以致用的能力。 举个例子&#xff0c;高三的…...

微服务入门篇:Nacos注册中心(Nacos安装,快速入门,多级存储,负载均衡,环境隔离,配置管理,热更新,集群搭建,nginx反向代理)

目录 1.Nacos安装1.官网下载2.解压到本地3.启动nacos 2.Nacos快速入门1.在父工程中导入nacos依赖2.给子项目添加客户端依赖3.修改对应服务的配置文件4.启动服务&#xff0c;查看nacos发现情况 3.Nacos服务多级存储模型4.NacosRule负载均衡5. 服务实例的权重设置6.环境隔离&…...

解决CORS错误(Spring Boot)

记录一下错误&#xff0c;以博客的形式 前言 跨域&#xff08;Cross-Origin&#xff09;是指在Web开发中&#xff0c;当一个Web应用试图从一个源&#xff08;域名、协议、端口组合&#xff09;获取资源时&#xff0c;该请求的目标与当前页面的源不同。具体来说&#xff0c;当一…...

NLP入门系列—词嵌入 Word embedding

NLP入门系列—词嵌入 Word embedding 2013年&#xff0c;Word2Vec横空出世&#xff0c;自然语言处理领域各项任务效果均得到极大提升。自从Word2Vec这个神奇的算法出世以后&#xff0c;导致了一波嵌入&#xff08;Embedding&#xff09;热&#xff0c;基于句子、文档表达的wor…...

JUnit5单元测试框架提供的注解

目录 第一章、注释在类上的注解1.1&#xff09;JUnit5注释在类上的注解集成测试&#xff1a;SpringBootTest集成测试&#xff1a;ExtendWith(SpringExtension.class)单元测试&#xff1a;ExtendWith(MockitoExtension.class)切片测试:WebMvcTest和DataJpaTest<font colorred…...

ThinkPHP 中使用Redis

环境.env [app] app_debug "1" app_trace ""[database] database "" hostname "127.0.0.1" hostport "" password "" prefix "ls_" username ""[redis] hostname "127.0.0.1…...

Go语言Gin框架安全加固:全面解析SQL注入、XSS与CSRF的解决方案

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。 前言 在使用 Gin 框架处理前端请求数据时&#xff0c;必须关注安全性问题&#xff0c;以防范常见的攻击…...

MySQL数据库基础与SELECT语句使用梳理

MySQL数据库基础与SELECT语句使用梳理 注意&#xff1a;本文操作全部在终端进行 数据库基础知识 什么是数据库 数据库&#xff08;database&#xff09;是保存有组织的数据的容器&#xff08;通常是一个文件或一组文件&#xff09;&#xff0c;实质上数据库是一个以某种 有组…...

scikit-learn 1.3.X 版本 bug - F1 分数计算错误

如果您正在使用 scikit-learn 1.3.X 版本&#xff0c;在使用 f1_score() 或 classification_report() 函数时&#xff0c;如果参数设置为 zero_division1.0 或 zero_divisionnp.nan&#xff0c;那么函数的输出结果可能会出错。错误的范围可能高达 100%&#xff0c;具体取决于数…...

Python面试题19-24

解释Python中的装饰器&#xff08;decorators&#xff09;是什么&#xff0c;它们的作用是什么&#xff1f; 装饰器是一种Python函数&#xff0c;用于修改其他函数的功能。它们允许在不修改原始函数代码的情况下&#xff0c;动态地添加功能。解释Python中的文件处理&#xff08…...

《Django+React前后端分离项目开发实战:爱计划》 01 项目整体概述

01 Introduction 《Django+React前后端分离项目开发实战:爱计划》 01 项目整体概述 Welcome to Beginning Django API wih React! This book focuses on they key tasks and concepts to get you started to learn and build a RESTFul web API with Django REST Framework,…...

从零开始 TensorRT(4)命令行工具篇:trtexec 基本功能

前言 学习资料&#xff1a; TensorRT 源码示例 B站视频&#xff1a;TensorRT 教程 | 基于 8.6.1 版本 视频配套代码 cookbook 参考源码&#xff1a;cookbook → 07-Tool → trtexec 官方文档&#xff1a;trtexec 在 TensorRT 的安装目录 xxx/TensorRT-8.6.1.6/bin 下有命令行…...

基于SpringBoot+Vue的校园博客管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 二、开发技术与环…...

基于 SpringBoot 和 Vue.js 的权限管理系统部署教程

大家后&#xff0c;我是 jonssonyan 在上一篇文章我介绍了我的新项目——基于 SpringBoot 和 Vue.js 的权限管理系统&#xff0c;本文主要介绍该系统的部署 部署教程 这里使用 Docker 进行部署&#xff0c;Docker 基于容器技术&#xff0c;它可以占用更少的资源&#xff0c;…...

Redis篇之集群

一、主从复制 1.实现主从作用 单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离。主节点用来写的操作&#xff0c;从节点用来读操作&#xff0c;并且主节点发生写操作后&#xff0c;会把数据同…...

JUnit 5 注解总结与解析

前言 大家好&#xff0c;我是chowley&#xff0c;通过前篇的JUnit实践&#xff0c;我对这个框架产生了好奇&#xff0c;除了断言判断&#xff0c;它还有哪些用处呢&#xff1f;下面来总结一下它的常见注解及作用。 正文 在Java单元测试中&#xff0c;JUnit是一种常用的测试框…...

CSS综合案例4

CSS综合案例4 1. 综合案例 我们来做一个静态的轮播图。 2. 分析思路 首先需要加载一张背景图进去需要4个小圆点&#xff0c;设置样式&#xff0c;并用定位和平移调整位置添加两个箭头&#xff0c;也是需要用定位和位移进行调整位置 3. 代码演示 html文件 <!DOCTYPE htm…...

WifiConfigStore初始化读取-Android13

WifiConfigStore初始化读取 1、StoreData创建并注册2、WifiConfigStore读取2.1 文件读取流程2.2 时序图2.3 日志 1、StoreData创建并注册 packages/modules/Wifi/service/java/com/android/server/wifi/WifiConfigManager.java mWifiConfigStore.registerStoreData(mNetworkL…...

【Spring源码解读!底层原理进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;底层原理高级进阶》 &#x1f680…...

从零开始手写mmo游戏从框架到爆炸(六)— 消息处理工厂

就好像门牌号一样&#xff0c;我们需要把消息路由到对应的楼栋和楼层&#xff0c;总不能像菜鸟一样让大家都来自己找数据吧。 首先这里我们参考了rabbitmq中的topic与tag模型&#xff0c;topic对应类&#xff0c;tag对应方法。 新增一个模块&#xff0c;专门记录路由eternity-…...

Go基础学习笔记-知识点

学习笔记记录了我在学习官方文档过程中记的要点&#xff0c;可以参考学习。 go build *.go 文件 编译 go run *.go 执行 go mod init 生成依赖管理文件 gofmt -w *.go 格式换名称的大小写用来控制方法的可见域主方法及包命名规范 package main //注意package的命名&#xff0…...

jvm几个常见面试题整理

1. Full GC触发机制有如下5种情况。 (1)调用System.gc()时&#xff0c;系统建议执行Full GC&#xff0c;但是不必然执行。(2)老年代空间不足。(3)方法区空间不足。(4)老年代的最大可用连续空间小于历次晋升到老年代对象的平均大小就会进行Full GC。(5)由Eden区、S0(From)区向S…...

ReentrantLock 和 公平锁

ReentrantLock 和 公平锁 一、基本介绍 ReentrantLock(重入锁) 是一个独占式锁&#xff0c;具有和synchronize的监视器锁基本相同的行为和语意。但和synchronized相比&#xff0c;它更加的灵活、强大、增加了轮询、超时、中断等高级功能以及可以创建公平和非公平锁。Reentran…...

使用Postman做API自动化测试

Postman最基本的功能用来重放请求&#xff0c;并且配合良好的response格式化工具。 高级点的用法可以使用Postman生成各个语言的脚本&#xff0c;还可以抓包&#xff0c;认证&#xff0c;传输文件。 仅仅做到这些还不能够满足一个系统的开发&#xff0c;或者说过于琐碎&#…...