Initial commit: PAR Server with Spring Boot 3.2, MyBatis-Plus, Flyway

This commit is contained in:
mediabot-pt
2026-06-29 10:43:24 +08:00
commit baa04b5138
60 changed files with 7043 additions and 0 deletions

37
par-common/pom.xml Normal file
View File

@@ -0,0 +1,37 @@
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.par</groupId>
<artifactId>par-server</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>par-common</artifactId>
<name>PAR Common</name>
<description>Common utilities, constants, and shared models</description>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,81 @@
package com.par.common.util;
import org.apache.commons.codec.digest.HmacUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* HMAC 签名工具类
*/
public class HmacUtil {
private static final String HMAC_ALGORITHM = "HmacSHA256";
/**
* 生成 HMAC-SHA256 签名
*
* @param secret 密钥
* @param data 待签名数据
* @return Base64 编码的签名
*/
public static String sign(String secret, String data) {
byte[] signature = new HmacUtils(HMAC_ALGORITHM, secret).hmac(data);
return Base64.getEncoder().encodeToString(signature);
}
/**
* 验证签名
*
* @param secret 密钥
* @param data 待签名数据
* @param signature 待验证的签名
* @return 是否匹配
*/
public static boolean verify(String secret, String data, String signature) {
String expected = sign(secret, data);
return MessageDigest.isEqual(
signature.getBytes(StandardCharsets.UTF_8),
expected.getBytes(StandardCharsets.UTF_8)
);
}
/**
* 构建签名内容字符串
* 格式: METHOD\nPATH\nTIMESTAMP\nBODY_SHA256
*/
public static String buildSignContent(String method, String path, long timestamp, String bodySha256) {
return method.toUpperCase() + "\n" + path + "\n" + timestamp + "\n" + bodySha256;
}
/**
* 计算 SHA-256 哈希
*/
public static String sha256(String input) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256 algorithm not available", e);
}
}
/**
* 生成匿名ID(邮箱SHA-256前16位)
*/
public static String generateAnonymousId(String email) {
String hash = sha256(email.toLowerCase().trim());
return hash.substring(0, 16);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}

View File

@@ -0,0 +1,25 @@
package com.par.common.util;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* 密码工具类
*/
public class PasswordUtil {
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
/**
* 加密密码
*/
public static String encode(String rawPassword) {
return encoder.encode(rawPassword);
}
/**
* 验证密码
*/
public static boolean matches(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}