fix(token,AxisInnovatorsBox) 修复报错NullPointerException,添加token持久化加解密逻辑

This commit is contained in:
Hydrogen
2025-08-18 02:16:16 +08:00
parent 2904258983
commit 628389150c
6 changed files with 115 additions and 5 deletions

View File

@@ -1,3 +1,3 @@
#Current Loaded Language
#Sat Aug 16 18:11:03 CST 2025
#Mon Aug 18 02:11:52 CST 2025
loadedLanguage=system\:zh_CN

View File

@@ -12,6 +12,8 @@ import com.axis.innovators.box.register.RegistrationSettingsItem;
import com.axis.innovators.box.register.RegistrationTool;
import com.axis.innovators.box.register.RegistrationTopic;
import com.axis.innovators.box.tools.*;
import com.axis.innovators.box.tools.Crypto.AESCryptoUtil;
import com.axis.innovators.box.tools.Crypto.Base64CryptoUtil;
import com.axis.innovators.box.util.PythonResult;
import com.axis.innovators.box.util.Tray;
import com.axis.innovators.box.verification.LoginResult;
@@ -94,14 +96,29 @@ public class AxisInnovatorsBox {
(Exception) throwable : new Exception(throwable));
});
// 初始化,这里为了能够在登录窗口使用主题,特意将初始化放在构造函数中
main.initLog4j2();
main.setTopic();
initLog4j2();
setTopic();
// 加载登录信息,如果没有,弹出登录弹窗,后续可以删掉默认弹出
// TODO: login window should not be show when AxisInnovatorsBox initialize,
// it should be show when user click login button.
try {
StateManager stateManager = new StateManager();
String token = stateManager.getState("loginToken");
String excryptedKey = "loginToken";
try {
excryptedKey = Base64CryptoUtil.base64Encode(excryptedKey);
} catch (Exception e) {
logger.error("Failed to encrypt key", e);
}
String encryptedToken = stateManager.getState(excryptedKey);
String token = null;
if (encryptedToken != null && !encryptedToken.isEmpty()) {
try {
token = AESCryptoUtil.decrypt(encryptedToken);
} catch (Exception ex) {
logger.error("Token 解密失败", ex);
token = null;
}
}
if (token == null || token.isEmpty()) {
LoginResult loginResult = CasdoorLoginWindow.showLoginDialogAndGetLoginResult();
if (loginResult == null) {
@@ -110,7 +127,8 @@ public class AxisInnovatorsBox {
JOptionPane.INFORMATION_MESSAGE);
} else if (loginResult.success()) {
loginData = loginResult.loginData();
stateManager.saveState("loginToken", loginResult.token());
String encrypted = AESCryptoUtil.encrypt(loginResult.token());
stateManager.saveState(excryptedKey, encrypted);
logger.info(
"Login result: token: " + loginResult.token() + ", user: " + loginResult.user());
JOptionPane.showMessageDialog(null, "登录成功", "登录",

View File

@@ -0,0 +1,50 @@
package com.axis.innovators.box.tools.Crypto;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.file.*;
import java.security.SecureRandom;
import java.util.Base64;
public class AESCryptoUtil {
private static final String KEY_FILE = System.getProperty("user.home") + "/.lingqi/.axis_box_key";
// 获取密钥Base64字符串长度16字节
public static byte[] getKeyBytes() throws Exception {
Path path = Paths.get(KEY_FILE);
if (Files.exists(path)) {
byte[] encrypted = Base64.getDecoder().decode(Files.readAllBytes(path));
return WindowsDPAPIUtil.unprotect(encrypted);
} else {
// 首次生成密钥
byte[] keyBytes = new byte[16];
new SecureRandom().nextBytes(keyBytes);
byte[] encrypted = WindowsDPAPIUtil.protect(keyBytes);
Files.createDirectories(path.getParent());
Files.write(path, Base64.getEncoder().encode(encrypted));
return keyBytes;
}
}
// 加密
public static String encrypt(String data) throws Exception {
byte[] keyBytes = getKeyBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encrypted);
}
// 解密
public static String decrypt(String encrypted) throws Exception {
byte[] keyBytes = getKeyBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decoded = Base64.getDecoder().decode(encrypted);
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted, "UTF-8");
}
}

View File

@@ -0,0 +1,15 @@
package com.axis.innovators.box.tools.Crypto;
import java.util.Base64;
public class Base64CryptoUtil {
public static String base64Encode(String input) {
return Base64.getEncoder().encodeToString(input.getBytes());
}
public static String base64Decode(String input) {
byte[] decodedBytes = Base64.getDecoder().decode(input);
return new String(decodedBytes);
}
}

View File

@@ -0,0 +1,12 @@
package com.axis.innovators.box.tools.Crypto;
import java.security.MessageDigest;
import java.util.Base64;
public class HashUtil {
public static String sha256(String input) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(hash); // 输出为Base64字符串
}
}

View File

@@ -0,0 +1,15 @@
package com.axis.innovators.box.tools.Crypto;
import com.sun.jna.platform.win32.Crypt32Util;
public class WindowsDPAPIUtil {
// 加密
public static byte[] protect(byte[] data) {
return Crypt32Util.cryptProtectData(data);
}
// 解密
public static byte[] unprotect(byte[] encrypted) {
return Crypt32Util.cryptUnprotectData(encrypted);
}
}