feat: user related logic refactor
This commit is contained in:
67
src/main/java/xin/merlin/myplayerbackend/utils/AESUtil.java
Normal file
67
src/main/java/xin/merlin/myplayerbackend/utils/AESUtil.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package xin.merlin.myplayerbackend.utils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Component
|
||||
public class AESUtil {
|
||||
|
||||
// 16 位密钥(必须 16/24/32 位)
|
||||
private final String key;
|
||||
|
||||
private static final String ALGORITHM = "AES";
|
||||
|
||||
public AESUtil(@Value("${aes.key}") String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/** 加密 */
|
||||
public String encrypt(String plainText) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM);
|
||||
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
|
||||
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64.getEncoder().encodeToString(encrypted);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("AES 加密失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** 解密 */
|
||||
public String decrypt(String cipherText) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM);
|
||||
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec);
|
||||
byte[] decoded = Base64.getDecoder().decode(cipherText);
|
||||
byte[] original = cipher.doFinal(decoded);
|
||||
return new String(original, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("AES 解密失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> decryptAndSplit(String cipherText) {
|
||||
String plainText = this.decrypt(cipherText); // 先解密
|
||||
String[] parts = plainText.split(":", 2); // 只分割一次,防止 email 里有 :
|
||||
|
||||
if (parts.length != 2) {
|
||||
throw new IllegalArgumentException("解密数据格式不正确:" + plainText);
|
||||
}
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("id", parts[0]);
|
||||
result.put("email", parts[1]);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ package xin.merlin.myplayerbackend.utils;
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xin.merlin.myplayerbackend.config.security.JwtProperties;
|
||||
import xin.merlin.myplayerbackend.entity.Account;
|
||||
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
@@ -13,6 +16,8 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JwtUtil {
|
||||
@@ -35,17 +40,28 @@ public class JwtUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
log.info("JWT 组件正在关闭...");
|
||||
// 如有线程池、定时任务、IO 连接,在这里 shutdown/close
|
||||
// 本例仅把引用置空,帮助 GC(可选)
|
||||
this.jwtParser = null;
|
||||
this.key = null;
|
||||
log.info("JWT 组件已关闭");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 JWT Token
|
||||
*/
|
||||
public String generateToken(String account, Integer id) {
|
||||
public String generateToken(Account account) {
|
||||
Date now = new Date();
|
||||
Date expireDate = new Date(now.getTime() + jwtProperties.getExpire() * 1000L);
|
||||
|
||||
return Jwts.builder()
|
||||
.subject(account)
|
||||
.claim("id", id)
|
||||
.claim("account", account)
|
||||
.subject(account.getAccount())
|
||||
.claim("id", account.getId())
|
||||
.claim("account", account.getAccount())
|
||||
.claim("character", account.getCharacter())
|
||||
.id(UUID.randomUUID().toString())
|
||||
.issuedAt(now)
|
||||
.expiration(expireDate)
|
||||
@@ -57,7 +73,7 @@ public class JwtUtil {
|
||||
/**
|
||||
* 解析 Token 获取 Claims
|
||||
*/
|
||||
public Claims getClaims(String token) {
|
||||
private Claims getClaims(String token) {
|
||||
try {
|
||||
Jws<Claims> jws = jwtParser.parseSignedClaims(token);
|
||||
System.out.println(jws.getPayload());
|
||||
@@ -95,6 +111,16 @@ public class JwtUtil {
|
||||
return claims.get("id", Integer.class);
|
||||
}
|
||||
|
||||
// public Integer getCharacter(String token) {
|
||||
// Claims claims = getClaims(token);
|
||||
// return claims.get("character", Integer.class);
|
||||
// }
|
||||
|
||||
public Boolean isAdmin(String token) {
|
||||
Claims claims = getClaims(token);
|
||||
return claims.get("character", Integer.class)==0;
|
||||
}
|
||||
|
||||
// 自定义异常类
|
||||
public static class TokenExpiredException extends RuntimeException {
|
||||
public TokenExpiredException(String message, Throwable cause) {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package xin.merlin.myplayerbackend.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class SHA256Util {
|
||||
|
||||
public static String sha256(String s) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
byte[] bytes = md.digest(s.getBytes(StandardCharsets.UTF_8));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) sb.append(String.format("%02x", b));
|
||||
return sb.toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,16 @@ public enum ResultCode {
|
||||
NOT_FOUND("404", "资源不存在"),
|
||||
SERVER_ERROR("500", "服务器内部错误"),
|
||||
|
||||
|
||||
// 自定义业务错误码
|
||||
|
||||
//账户相关
|
||||
ACCOUNT_EXIST("2001","账户已存在"),
|
||||
ACCOUNT_EXIST("3001","账户已存在"),
|
||||
ACCOUNT_NOT_INIT("3002","账户未初始化"),
|
||||
ACCOUNT_PWD_ERROR("3003","账户密码错误"),
|
||||
ACCOUNT_INFO_LOST("3004","账户信息丢失"),
|
||||
ACCOUNT_ILLEGAL_CHANGE("3005","账户非法篡改"),
|
||||
ACCOUNT_PERMISSION_DENY("3006","用户权限不足"),
|
||||
|
||||
//用户相关
|
||||
USER_BANNED("4000","用户被封禁"),
|
||||
@@ -28,7 +34,7 @@ public enum ResultCode {
|
||||
USER_VERIFICATION_ERROR("4005","验证码不存在或错误"),
|
||||
USER_SEND_TOO_FAST("4006","用户请求过快"),
|
||||
USER_SEND_TOO_OFTEN("4007","请求次数过多,已被限制"),
|
||||
ORDER_NOT_FOUND("4000", "订单不存在"),
|
||||
USER_ILLEGAL_REQUEST("4008", "用户非法请求"),
|
||||
|
||||
//邮箱相关
|
||||
MAIL_ACCOUNT_NOT_PROVIDED("4101","未提供验证码接受账户"),
|
||||
@@ -36,7 +42,10 @@ public enum ResultCode {
|
||||
MAIL_INFO_LOST("4103","验证信息丢失"),
|
||||
MAIL_VERIFY_FAIL_TOO_MANY("4104","验证码错误过多,请重新申请验证码"),
|
||||
MAIL_VERIFY_NOT_EXIST("4105","验证码元素丢失,请重新申请验证码"),
|
||||
MAIL_VERIFY_CODE_ERROR("4106","验证码错误,请重新输入");
|
||||
MAIL_VERIFY_CODE_ERROR("4106","验证码错误,请重新输入"),
|
||||
|
||||
//审核相关
|
||||
AUDIT_NO_RECORD("4201","无审核记录条目");
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user