软件增加license管理
FilterConfig.java
全局过滤器配置 ,对需要拦截的路径进行配置
package cn.vppark.whdev.license_test.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Filter配置
*
* @author Mark sunlightcs@gmail.com
*/
@Configuration
public class FilterConfig {
@Value("${app.license:}")
private String license;
@Bean
public FilterRegistrationBean licenseFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new LicenseFilter(license));
registration.addUrlPatterns("/*");
registration.setName("licenseFilter");
registration.setOrder(Integer.MAX_VALUE);
return registration;
}
}
LicenseFilter.java
package cn.vppark.whdev.license_test.config;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
/**
* @Description: 证书校验
* @date: 2024年4月9日 下午12:39:48
* @Copyright:
*/
public class LicenseFilter implements Filter {
private String license;
/**
* 公钥
*/
private final String publicKey = "your public key";
public LicenseFilter(String license) {
this.license = license;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//设置返回参数
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("text/html; charset=UTF-8");
try {
if (this.license == null || license.isEmpty()) {
// 优先使用配置文件的证书,因为调试运行的时候,会清空target目录,导致证书文件丢失
this.license = IOUtils.toString(new FileInputStream(getLicensePath()), StandardCharsets.UTF_8);
}
//解密证书
String licenseContent = verifyLicense(this.license);
JSONObject json = JSONObject.parseObject(licenseContent);
//获取过期时间
Date expire = json.getDate("expire");
httpServletResponse.setHeader("license-expire", expire.toString());
//判断证书是否过期
if (expire.getTime() < System.currentTimeMillis()) {
httpServletResponse.getWriter().write("软件授权过期!");
return;
}
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
} catch (FileNotFoundException e) {
httpServletResponse.getWriter().write("证书文件丢失,请联系管理员!");
e.printStackTrace();
return;
} catch (Exception e) {
httpServletResponse.getWriter().write("证书文件已损坏,请联系管理员!");
e.printStackTrace();
return;
}
chain.doFilter(request, response);
}
/**
* @throws
* @Description: 根据公钥解密字符串
* @param: licenseContent 证书内容
*/
public String verifyLicense(String licenseContent) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey))));
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(licenseContent));
String decryptedString = new String(decryptedBytes);
// 打印解密后的证书内容
System.out.println("licenseContent: " + decryptedString);
return decryptedString;
}
/**
* @throws
* @Description: 获取license完整路径
*/
private String getLicensePath() throws URISyntaxException {
URL classUrl = this.getClass().getProtectionDomain().getCodeSource().getLocation();
URI uri = classUrl.toURI();
Path path;
if (uri.getScheme().equals("jar")) {
// 如果是一个JAR URL,我们需要找到JAR文件本身
String jarPath = uri.getSchemeSpecificPart();
jarPath = jarPath.substring(0, jarPath.indexOf('!'));
path = Paths.get(new URI(jarPath)).getParent();
} else {
// 如果不是JAR URL,则可能是直接从文件系统加载的类
path = Paths.get(uri);
}
String licensePath = path.resolve("license/license").toString();
// 打印证书路径
System.out.println("licensePath: " + licensePath);
return licensePath;
}
}