mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-16 20:33:03 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8ba451d18 | ||
|
|
77758db463 | ||
|
|
6c58598a8e | ||
|
|
3ac35230a3 |
@@ -3,7 +3,7 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml"><img src="https://img.shields.io/github/actions/workflow/status/qaiu/netdisk-fast-download/maven.yml?branch=v0.1.9b2&style=flat"></a>
|
||||
<a href="https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml"><img src="https://img.shields.io/github/actions/workflow/status/qaiu/netdisk-fast-download/maven.yml?branch=main&style=flat"></a>
|
||||
<a href="https://www.oracle.com/cn/java/technologies/downloads"><img src="https://img.shields.io/badge/jdk-%3E%3D17-blue"></a>
|
||||
<a href="https://vertx-china.github.io"><img src="https://img.shields.io/badge/vert.x-4.5.6-blue?style=flat"></a>
|
||||
<a href="https://raw.githubusercontent.com/qaiu/netdisk-fast-download/master/LICENSE"><img src="https://img.shields.io/github/license/qaiu/netdisk-fast-download?style=flat"></a>
|
||||
|
||||
185
web-service/src/main/java/cn/qaiu/lz/common/util/JwtUtil.java
Normal file
185
web-service/src/main/java/cn/qaiu/lz/common/util/JwtUtil.java
Normal file
@@ -0,0 +1,185 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.lz.web.model.SysUser;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* JWT工具类,用于生成和验证JWT token
|
||||
*/
|
||||
public class JwtUtil {
|
||||
|
||||
private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; // token过期时间,24小时
|
||||
private static final String SECRET_KEY = "netdisk-fast-download-jwt-secret-key"; // 密钥
|
||||
private static final String ALGORITHM = "HmacSHA256";
|
||||
|
||||
/**
|
||||
* 生成JWT token
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return JWT token
|
||||
*/
|
||||
public static String generateToken(SysUser user) {
|
||||
long expireTime = getExpireTime();
|
||||
|
||||
// Header
|
||||
JsonObject header = new JsonObject()
|
||||
.put("alg", "HS256")
|
||||
.put("typ", "JWT");
|
||||
|
||||
// Payload
|
||||
JsonObject payload = new JsonObject()
|
||||
.put("id", user.getId())
|
||||
.put("username", user.getUsername())
|
||||
.put("role", user.getRole())
|
||||
.put("exp", expireTime)
|
||||
.put("iat", System.currentTimeMillis())
|
||||
.put("iss", "netdisk-fast-download");
|
||||
|
||||
// Base64 encode header and payload
|
||||
String encodedHeader = Base64.getUrlEncoder().withoutPadding().encodeToString(header.encode().getBytes(StandardCharsets.UTF_8));
|
||||
String encodedPayload = Base64.getUrlEncoder().withoutPadding().encodeToString(payload.encode().getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// Create signature
|
||||
String signature = hmacSha256(encodedHeader + "." + encodedPayload, SECRET_KEY);
|
||||
|
||||
// Combine to form JWT
|
||||
return encodedHeader + "." + encodedPayload + "." + signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用HMAC-SHA256算法生成签名
|
||||
*
|
||||
* @param data 要签名的数据
|
||||
* @param key 密钥
|
||||
* @return 签名
|
||||
*/
|
||||
private static String hmacSha256(String data, String key) {
|
||||
try {
|
||||
Mac sha256Hmac = Mac.getInstance(ALGORITHM);
|
||||
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
|
||||
sha256Hmac.init(secretKey);
|
||||
byte[] signedBytes = sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(signedBytes);
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
throw new RuntimeException("Error creating HMAC SHA256 signature", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证JWT token
|
||||
*
|
||||
* @param token JWT token
|
||||
* @return 如果token有效返回true,否则返回false
|
||||
*/
|
||||
public static boolean validateToken(String token) {
|
||||
try {
|
||||
String[] parts = token.split("\\.");
|
||||
if (parts.length != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String encodedHeader = parts[0];
|
||||
String encodedPayload = parts[1];
|
||||
String signature = parts[2];
|
||||
|
||||
// 验证签名
|
||||
String expectedSignature = hmacSha256(encodedHeader + "." + encodedPayload, SECRET_KEY);
|
||||
if (!expectedSignature.equals(signature)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证过期时间
|
||||
String payload = new String(Base64.getUrlDecoder().decode(encodedPayload), StandardCharsets.UTF_8);
|
||||
JsonObject payloadJson = new JsonObject(payload);
|
||||
long expTime = payloadJson.getLong("exp", 0L);
|
||||
|
||||
return System.currentTimeMillis() < expTime;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从token中获取用户ID
|
||||
*
|
||||
* @param token JWT token
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserIdFromToken(String token) {
|
||||
String[] parts = token.split("\\.");
|
||||
if (parts.length != 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Base64解码
|
||||
String payload = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8);
|
||||
JsonObject jsonObject = new JsonObject(payload);
|
||||
return jsonObject.getString("id");
|
||||
}
|
||||
|
||||
/**
|
||||
* 从token中获取用户名
|
||||
*
|
||||
* @param token JWT token
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getUsernameFromToken(String token) {
|
||||
String[] parts = token.split("\\.");
|
||||
if (parts.length != 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Base64解码
|
||||
String payload = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8);
|
||||
JsonObject jsonObject = new JsonObject(payload);
|
||||
return jsonObject.getString("username");
|
||||
}
|
||||
|
||||
/**
|
||||
* 从token中获取用户角色
|
||||
*
|
||||
* @param token JWT token
|
||||
* @return 用户角色
|
||||
*/
|
||||
public static String getRoleFromToken(String token) {
|
||||
String[] parts = token.split("\\.");
|
||||
if (parts.length != 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Base64解码
|
||||
String payload = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8);
|
||||
JsonObject jsonObject = new JsonObject(payload);
|
||||
return jsonObject.getString("role");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取过期时间
|
||||
*
|
||||
* @return 过期时间戳
|
||||
*/
|
||||
private static long getExpireTime() {
|
||||
return System.currentTimeMillis() + EXPIRE_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将过期时间戳转换为LocalDateTime
|
||||
*
|
||||
* @param expireTime 过期时间戳
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime getExpireTimeAsLocalDateTime(long expireTime) {
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochMilli(expireTime), ZoneId.systemDefault());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 密码加密工具类
|
||||
* 使用SHA-256算法加盐进行密码加密和验证
|
||||
*/
|
||||
public class PasswordUtil {
|
||||
|
||||
private static final String ALGORITHM = "SHA-256";
|
||||
private static final int SALT_LENGTH = 16; // 盐的长度
|
||||
private static final String DELIMITER = ":"; // 用于分隔盐和哈希值的分隔符
|
||||
|
||||
/**
|
||||
* 对密码进行加密
|
||||
*
|
||||
* @param plainPassword 明文密码
|
||||
* @return 加密后的密码(格式:salt:hash)
|
||||
*/
|
||||
public static String hashPassword(String plainPassword) {
|
||||
if (plainPassword == null || plainPassword.isEmpty()) {
|
||||
throw new IllegalArgumentException("密码不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
// 生成随机盐
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte[] salt = new byte[SALT_LENGTH];
|
||||
random.nextBytes(salt);
|
||||
|
||||
// 计算哈希值
|
||||
MessageDigest md = MessageDigest.getInstance(ALGORITHM);
|
||||
md.update(salt);
|
||||
byte[] hashedPassword = md.digest(plainPassword.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// 将盐和哈希值编码为Base64并拼接
|
||||
String saltBase64 = Base64.getEncoder().encodeToString(salt);
|
||||
String hashBase64 = Base64.getEncoder().encodeToString(hashedPassword);
|
||||
|
||||
// 返回格式:salt:hash
|
||||
return saltBase64 + DELIMITER + hashBase64;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("加密算法不可用", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证密码是否正确
|
||||
*
|
||||
* @param plainPassword 明文密码
|
||||
* @param hashedPassword 加密后的密码(格式:salt:hash)
|
||||
* @return 如果密码匹配返回true,否则返回false
|
||||
*/
|
||||
public static boolean checkPassword(String plainPassword, String hashedPassword) {
|
||||
if (plainPassword == null || hashedPassword == null || hashedPassword.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 分割盐和哈希值
|
||||
String[] parts = hashedPassword.split(DELIMITER);
|
||||
if (parts.length != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String saltBase64 = parts[0];
|
||||
String hashBase64 = parts[1];
|
||||
|
||||
// 解码盐
|
||||
byte[] salt = Base64.getDecoder().decode(saltBase64);
|
||||
|
||||
// 使用相同的盐计算哈希值
|
||||
MessageDigest md = MessageDigest.getInstance(ALGORITHM);
|
||||
md.update(salt);
|
||||
byte[] calculatedHash = md.digest(plainPassword.getBytes(StandardCharsets.UTF_8));
|
||||
String calculatedHashBase64 = Base64.getEncoder().encodeToString(calculatedHash);
|
||||
|
||||
// 比较计算出的哈希值和存储的哈希值
|
||||
return hashBase64.equals(calculatedHashBase64);
|
||||
} catch (Exception e) {
|
||||
// 如果发生异常(例如格式不正确),返回false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user