0%

Java 使用 license

使用 truelicense

  1. 应用程序可以创建以及验证绑定给用户、系统等实体的 license。
  2. 防止用户随意拷贝软件和 license。
  3. licenses 可以是永久性的或者临时性的(在某个特定时期内有效)
  4. licenses 的验证由 JAVA Security API 提供的数字签名机制来实现。
  5. license 安装模块需要用特殊机制对其进行保护,以防被反编译轻易破解。

管理端生成密钥

1
2
3
4
5
6
7
# 1、生成密钥对
keytool -genkey -alias dsa_private_key -keyalg DSA -keysize 1024 -dname "CN=maxzhao, OU=maxzhao, O=maxzhao_org, L=nanjing, ST=jiangsu, C=China" \
-validity 36500 -keystore dsa_private_key_store.jks -storepass maxzhao_pwd -keypass maxzhao_pwd
# 2、导出公钥
keytool -export -alias dsa_private_key -file dsa_certfile.cer -keystore dsa_private_key_store.jks -storepass maxzhao_pwd
# 3、证书文件导入到公钥库
keytool -import -alias dsa_public_cert -file dsa_certfile.cer -keystore dsa_public_certs_store.jks -storepass maxzhao_pwd

服务段生成证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.license;


import de.schlichtherle.license.*;

import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Properties;
import java.util.prefs.Preferences;

/**
* 生成证书
*/
public class CreateLicense {
public static void main(String[] args) {
CreateLicense cLicense = new CreateLicense();
cLicense.setParam("/param.properties");
//生成证书
boolean b = cLicense.create();
}

private static String PRIVATE_ALIAS = "";
private static String KEY_PWD = "";
private static String STORE_PWD = "";
private static String SUB_JECT = "";
private static String LIC_PATH = "";
private static String PRI_PATH = "";
private static String ISSUED_TIME = "";
private static String NOT_BEFORE = "";
private static String NOT_AFTER = "";
private static String CONSUMER_TYPE = "";
private static int CONSUMER_AMOUNT = 0;
private static String INFO = "";
// X500 Principal
private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = new X500Principal("CN=maxzhao, OU=maxzhao, O=maxzhao_org, L=nanjing, ST=jiangsu, C=China");

public void setParam(String propertiesPath) { // 获取参数
Properties prop = new Properties();
InputStream in = getClass().getResourceAsStream(propertiesPath);
try {
prop.load(in);
} catch (IOException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
PRIVATE_ALIAS = prop.getProperty("privateAlias");
KEY_PWD = prop.getProperty("keyPwd");
STORE_PWD = prop.getProperty("storePwd");
SUB_JECT = prop.getProperty("subJect");
KEY_PWD = prop.getProperty("keyPwd");
LIC_PATH = prop.getProperty("licPath");
PRI_PATH = prop.getProperty("priPath"); //license content
ISSUED_TIME = prop.getProperty("issuedTime");
NOT_BEFORE = prop.getProperty("notBefore");
NOT_AFTER = prop.getProperty("notAfter");
CONSUMER_TYPE = prop.getProperty("consumerType");
CONSUMER_AMOUNT = Integer.valueOf(prop.getProperty("consumerAmount"));
INFO = prop.getProperty("info");
}

/**
* 证书发布者端执行
*/
public boolean create() {
try {
LicenseManager licenseManager = new LicenseManager(initLicenseParams());
licenseManager.store((createLicenseContent()), new File(LIC_PATH));
} catch (Exception e) {
e.printStackTrace();
System.out.println("客户端证书生成失败!");
return false;
}
System.out.println("服务器端生成证书成功!");
return true;
}

/**
* 返回生成证书时需要的参数
*/
private static LicenseParam initLicenseParams() {
Preferences preference = Preferences.userNodeForPackage(LicenseCreator.class);
// 设置对证书内容加密的对称密码
CipherParam cipherParam = new DefaultCipherParam(STORE_PWD);
KeyStoreParam privateStoreParam = new DefaultKeyStoreParam(LicenseCreator.class, PRI_PATH, PRIVATE_ALIAS, STORE_PWD, KEY_PWD);
return new DefaultLicenseParam(SUB_JECT, preference, privateStoreParam, cipherParam);
}

/**
* 从外部表单拿到证书的内容
*/
public final static LicenseContent createLicenseContent() {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
LicenseContent content = null;
content = new LicenseContent();
content.setSubject(SUB_JECT);
content.setHolder(DEFAULT_HOLDER_AND_ISSUER);
content.setIssuer(DEFAULT_HOLDER_AND_ISSUER);
try {
content.setIssued(format.parse(ISSUED_TIME));
content.setNotBefore(format.parse(NOT_BEFORE));
content.setNotAfter(format.parse(NOT_AFTER));
} catch (ParseException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
content.setConsumerType(CONSUMER_TYPE);
content.setConsumerAmount(CONSUMER_AMOUNT);
content.setInfo(INFO); // 扩展
content.setExtra(new Object());
return content;
}
}

客户端使用证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.license;

import de.schlichtherle.license.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.prefs.Preferences;

/**
* 校验证书
*/
public class VerifyLicense {

public static void main(String[] args) {
VerifyLicense license = new VerifyLicense();
license.setParam("/public-param.properties");
license.verify();
}

private static String PUBLIC_ALIAS = "";
private static String STORE_PWD = "";
private static String SUB_JECT = "";
private static String LIC_PATH = "";
private static String PUB_PATH = "";

public void setParam(String propertiesPath) {
// 获取参数
Properties prop = new Properties();
InputStream in = getClass().getResourceAsStream(propertiesPath);
try {
prop.load(in);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PUBLIC_ALIAS = prop.getProperty("publicAlias");
STORE_PWD = prop.getProperty("storePwd");
SUB_JECT = prop.getProperty("subJect");
LIC_PATH = prop.getProperty("licPath");
PUB_PATH = prop.getProperty("pubPath");
}

/**
* 证书使用者端执行
*/
public boolean verify() {
LicenseManager licenseManager = new LicenseManager(initLicenseParams());
// 安装证书
try {
licenseManager.install(new File(LIC_PATH));
System.out.println("客户端安装证书成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("客户端证书安装失败!");
return false;
}
// 验证证书
try {
licenseManager.verify();
System.out.println("客户端验证证书成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("客户端证书验证失效!");
return false;
}
return true;
}

/**
* 返回验证证书需要的参数
*/
private static LicenseParam initLicenseParams() {
Preferences preference = Preferences.userNodeForPackage(VerifyLicense.class);
CipherParam cipherParam = new DefaultCipherParam(STORE_PWD);
KeyStoreParam privateStoreParam = new DefaultKeyStoreParam(VerifyLicense.class, PUB_PATH, PUBLIC_ALIAS, STORE_PWD, null);
return new DefaultLicenseParam(SUB_JECT, preference, privateStoreParam, cipherParam);
}
}

maven 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<dependencies>
<dependency>
<groupId>de.schlichtherle.truelicense</groupId>
<artifactId>truelicense-core</artifactId>
<version>1.33</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.77</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
</dependencies>

param.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# alias
privateAlias=dsa_private_key
keyPwd=maxzhao_pwd
storePwd=maxzhao_pwd
subJect=bigdata
# 绝对路径
licPath=/temp/bigdata-out-18.lic
priPath=/dsa_private_key_store.jks
##########license content###########
issuedTime=2014-04-01
notBefore=2014-04-01
notAfter=2024-07-18
consumerType=user
consumerAmount=1
# other info
info=this is a license

public-param.properties

1
2
3
4
5
6
7
8
9
# alias
publicAlias=dsa_public_cert
storePwd=maxzhao_pwd
# 主题
subJect=bigdata
# 绝对路径
licPath=/temp/bigdata-out-18.lic
pubPath=/dsa_public_certs_store.jks

本文地址: https://github.com/maxzhao-it/blog/post/56235478467467/

Git拉取tag的更新

要拉取全部包括tag需要使用

1
2
3
git -c credential.helper= -c core.quotepath=false -c log.showSignature=false fetch origin --recurse-submodules=no --progress --prune
# 或者
git fetch origin

正常情况下,只能拉倒当前的分支

1
git pull origin main 

本文地址: https://github.com/maxzhao-it/blog/post/a1bc7e95/

log4j2读取Application.yml中的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 默认日志输出路径
*
* @author maxzhao
*/
@Component
public class LoggerListener implements ApplicationListener<ApplicationEvent>, Ordered {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ConfigurableEnvironment environment = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment();
String property = environment.getProperty("spring.application.name");
System.setProperty("empower.log.path", property);
}
}

@Override
public int getOrder() {
return LoggingApplicationListener.DEFAULT_ORDER - 1;
}
}

启动类

1
2
3
4
5
6
7
8
9
10
public class DataHubApplication {


public static void main(String[] args) {
SpringApplication application = new SpringApplication(DataHubApplication.class);
application.addListeners(new LoggerListener());
ConfigurableApplicationContext context = application.run(args);
SpringBootUtils.setApplicationContent(context);
}
}

本文地址: https://github.com/maxzhao-it/blog/post/3c950ad/

直接清除

安装好python3之后执行

1
2
3
4
5
pip install git-filter-repo
# 删除所有大于 10M的文件
git filter-repo --strip-blobs-bigger-than 10M --force
# 删除某个具体的文件
git filter-repo --path path/to/file.ext --invert-paths

找到 .git\filter-repo\commit-map 文件,备份一下

1
2
3
4
git config --unset remote.origin.mirror
git push origin --force 'refs/heads/*'
# git push origin --force 'refs/tags/*'
git push origin --force 'refs/replace/*'

到 gitlab的 Repository cleanup 上传

Gitlab 说明文档

找到大文件(git < 2.40)

1
2
3
4
5
6
7
git commit -am "commit all"
git gc
git count-objects -v
# 第三列是大小:SHA-1 type size size-in-packfile offset-in-packfile
git verify-pack -v .git/objects/pack/pack-xxxx.idx | sort -k 3 -n | tail -3
# windows
git verify-pack -v .git/objects/pack/pack-xxxx.idx >> 1.txt

根据sha-1 列出所有commit

1
2
3
git rev-list --objects --all |grep b8b2c97e4327aadb5d5b5926a2a8aaa8dc0c5b1f
# windows
git rev-list --objects --all |findstr “b8b2c97e4327aadb5d5b5926a2a8aaa8dc0c5b1f”

移除

1
2
3
4
5
6
git log --pretty=oneline --branches -- docs/.vuepress/public/nacos/nacos-server-2.2.0.1.tar.gz
# 输出
# 91b26ddfe8a744d266498fc6d176b7b75f0113f2 docs:文档
# ea773ea3347b48d132c0ddfa1ae30541c831ed1e docs:build 部署中间件内容迁移
# 删除所有commit
git filter-branch --index-filter 'git rm --cached --ignore-unmatch docs/.vuepress/public/nacos/nacos-server-2.2.0.1.tar.gz' -- ea773ea3347b48d132c0ddfa1ae30541c831ed1e..

删除空间引用

1
2
3
rm -rf .git/refs/original
rm -rf .git/logs/
git gc

查看空间

1
git count-objects -v

本文地址: https://github.com/maxzhao-it/blog/post/d3a05225/

K8S部署Logstash

挂载路径

容器内绝对路径

1
/usr/share/logstash/pipeline/logstash.conf

容器内路径

1
~/pipeline/logstash.conf

K8S部署Filebeat

挂载路径

容器内绝对路径

1
/usr/share/filebeat/filebeat.yml

容器内路径

1
~/filebeat.yml

挂载路径 HostPath

  • /var/lib/docker/containers
  • /var/log

env

  • NODE_NAME 1

K8S部署Kibana

挂载路径

容器内绝对路径

1
/usr/share/kibana/config/kibana.yml

容器内路径

1
~/kibana.yml

本文地址: https://github.com/maxzhao-it/blog/post/9074123121/

直接检索出所有包含字符串的文件

1
find /path/to/search -type f -name "application.yml" -exec grep -l "test" {} +

查看所有包含字符串的文件内上下文

1
find /path/to/search -type f -name "application.yml" -exec grep "empower" {} +

替换所有文件中的字符串

1
2
3
find /path/to/search -type f -name "application.yml" -exec sed -i 's/empower/empower-test/g' {} +
# 之查看不替换,可以不用 sed 的 -i 命令
find /path/to/search -type f -name "application.yml" -exec sed 's/empower/empower-test/g' {} +

本文地址: https://github.com/maxzhao-it/blog/post/aa3ad85532434/

打开 GPEDIT.msc
点击** 计算机配置——管理模板——window组件——远程桌面服务——远程桌面会话主机——连接**
允许用户通过使用远程桌面服务进行远程连接 打开
限制链接数量 打开 ,填写数量
将远程桌面服务用户限制到单独的远程桌面服务回话 禁用

本文地址: https://github.com/maxzhao-it/blog/post/f4328759/

1
2
3
4
5
6
7
8
9
10
11
12
13
title: SpringBoot使用外部目录放jar包
author: maxzhao

tags:
- Java
- Maven

categories:
- SpringBoot
- Maven

abbrlink: 31330vxcv
date: 2024-06-16 00:00:00

SpringBoot使用外部目录放jar包

配置 pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.xxxxApplication</mainClass>
<layout>ZIP</layout>
<includeSystemScope>true</includeSystemScope>
<fork>true</fork>
<includes>
<include>
<groupId>no</groupId>
<artifactId>no</artifactId>
</include>
</includes>
</configuration>
</plugin>

这里配置所有的jar都不要。

也可以单独去除某些依赖

1
2
3
4
5
6
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>

配合 maven-dependency-plugin 输出jar包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/libs/</outputDirectory>
<includeScope>runtime</includeScope>
<!-- 以下排除 test 范围的依赖 -->
<excludeScope>test</excludeScope>
<overWriteReleases>true</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<!--包含的jar,多个用英文逗号分隔-->
<includeArtifactIds>bcprov-jdk15on</includeArtifactIds>
<!--不包含的jar,多个用英文逗号分隔-->
<excludeArtifactIds>bcprov-jdk15on</excludeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>

本文地址: https://github.com/maxzhao-it/blog/post/0/

Redhat上部署vsftp权限控制
1背景
现场需要部署一个ftp系统,供数据交换使用。
以前惯用的方式是通过linux的用户来创建。
本次做了另外一个尝试,采用虚拟用户进行配置。
2配置过程
2.1vsftpd配置
执行命令: vi /etc/vsftpd/vsftpd.conf 修改/etc/vsftpd/vsftpd.conf,增加如下配置项:
pam_service_name=vsftpd
userlist_enable=YES
userlist_deny=YES
#tcp_wrapper=YES

anonymous_enable=NO
use_localtime=YES
ascii_upload_enable=YES
ascii_download_enable=YES

chroot_local_user=YES
chroot_list_enable=YES
local_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list

xferlog_enable=YES
local_umask=022

listen_port=21
connect_from_port_20=YES

idle_session_timeout=1000
data_connection_timeout=1000
accept_timeout=5
connect_timeout=1

guest_enable=YES
guest_username=ftpuser
user_config_dir=/etc/vsftpd/vuser_conf

pasv_min_port=10060
pasv_max_port=10090

write_enable=YES
local_umask=022
virtual_use_local_privs=NO
download_enable=YES
anon_world_readable_only=NO
anon_mkdir_write_enable=YES
anon_upload_enable=YES
anon_other_write_enable=YES

xferlog_enable=YES
xferlog_std_format=YES
xferlog_file=/var/log/vsftp/xferlog.log
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftp/vsftpd.log
max_per_ip=200
max_clients=500
2.2创建chroot_list文件
执行命令touch /etc/vsftpd/chroot_list,在/etc/vsftpd目录下创建chroot_list文件,可将可访问所有目录的用户写在里面,一行一个。
2.3创建linux用户
通过命令useradd -g ftp -s /sbin/nologin ftpuser创建ftp使用的用户ftpuser。
2.4配置用户信息
2.4.1用户数据库
使用vi命令在/etc/vsftpd目录下创建用户文件passwd,单数行为用户名,双数行为密码。
执行命令db_load -T -t hash -f /etc/vsftpd/passwd /etc/vsftpd/passwd.db。
2.4.2创建用户文件
使用命令mkdir /etc/vsftpd/vuser_conf在/etc/vsftpd下创建目录vuser_conf。
在vuser_conf目录下创建用户同名文件。
文件内容如下:
local_root=/ftpdata
write_enable=YES
local_umask=022
virtual_use_local_privs=NO
#下载
download_enable=YES
#只读
anon_world_readable_only=NO
#创建目录
anon_mkdir_write_enable=YES
#上传
anon_upload_enable=YES
#删除
anon_other_write_enable=YES
anon_umask=022
2.5修改用户目录权限
ftpuser必须对/ftpdata无写权限
在/ftpdata目录下创建新的有读写权限目录
mkdir /ftpdata/data
chown ftpuser: /ftpdata/data
2.6配置校验
使用命令vi /etc/pam.d/vsftpd修改/etc/pam.d/vsftpd,清空内容,修改为:
auth sufficient /lib64/security/pam_userdb.so db=/etc/vsftpd/passwd
account sufficient /lib64/security/pam_userdb.so db=/etc/vsftpd/passwd
2.7配置目录权限
若已关闭selinux,则跳过此步骤。

在ftp目录下,执行如下命令,查看目录权限:
sestatus -b| grep ftp

执行如下命令授权:
setsebool -P ftp_home_dir on
setsebool -P allow_ftpd_full_access on
2.8打开端口
firewall-cmd –add-port=21/tcp –permanent
firewall-cmd –add-port=10060-10090/tcp –permanent
2.9重启vsftpd服务

本文地址: https://github.com/maxzhao-it/blog/post/54531fghfgd/

需要排除某个 Bean 时,

通过类排除 ASSIGNABLE_TYPE

1
2
3
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
value = {DEMO.class})}, basePackages = {"com"})

通过类排除

1
2
3
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
value = {DEMO.class})}, basePackages = {"com"})

基于注解排除 ANNOTATION

1
2
3
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = MyAnnotation.class )}, basePackages = {"com"})

通过正则排除 REGEX

1
2
3
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.REGEX,
pattern = "com\.maxzhao\..*\.controller\..*" )}, basePackages = {"com"})

本文地址: https://github.com/maxzhao-it/blog/post/31330vxcvgfgdfg/