Commit da0e4741 by zhangxingmin

Merge remote-tracking branch 'origin/test' into prod

parents 39b911fa a1183e83
...@@ -6,7 +6,7 @@ LABEL maintainer="zxm<2060197959@qq.com>" ...@@ -6,7 +6,7 @@ LABEL maintainer="zxm<2060197959@qq.com>"
RUN mkdir -p /home/app RUN mkdir -p /home/app
# 拷贝项目jar - 使用可执行的 fat JAR # 拷贝项目jar - 使用可执行的 fat JAR
COPY target/yd-auth-core-1.0-SNAPSHOT-exec.jar /home/app/yd-auth-core.jar COPY target/yd-auth-core-1.0-SNAPSHOT-exec.jar /home/app/yd-auth-core.jar
# 执行命令启动jar # 执行命令启动jar,并设置JVM内存参数
ENTRYPOINT ["java", "-jar", "/home/app/yd-auth-core.jar"] ENTRYPOINT ["java", "-Xmx256m", "-Xms128m", "-jar", "/home/app/yd-auth-core.jar"]
# 暴露端口 # 暴露端口
EXPOSE 9001 EXPOSE 9001
...@@ -5,6 +5,7 @@ import io.jsonwebtoken.*; ...@@ -5,6 +5,7 @@ import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecurityException; import io.jsonwebtoken.security.SecurityException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
...@@ -12,16 +13,14 @@ import org.springframework.security.core.GrantedAuthority; ...@@ -12,16 +13,14 @@ import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.util.Collection; import java.util.*;
import java.util.Date;
import java.util.Base64;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* JWT令牌提供者 * JWT令牌提供者
* 修复了密钥长度不足的问题,并优化了异常处理 * 修复了密钥长度不足的问题,并优化了异常处理
*/ */
@Slf4j
@Component @Component
public class JwtTokenProvider { public class JwtTokenProvider {
...@@ -30,7 +29,7 @@ public class JwtTokenProvider { ...@@ -30,7 +29,7 @@ public class JwtTokenProvider {
private String jwtSecret; private String jwtSecret;
@Value("${jwt.expiration}") // 默认24小时(单位毫秒) @Value("${jwt.expiration}") // 默认24小时(单位毫秒)
private int jwtExpiration; private long jwtExpiration;
/** /**
* 生成JWT令牌 * 生成JWT令牌
...@@ -40,6 +39,7 @@ public class JwtTokenProvider { ...@@ -40,6 +39,7 @@ public class JwtTokenProvider {
throw new JwtAuthenticationException("无法从空认证信息生成令牌"); throw new JwtAuthenticationException("无法从空认证信息生成令牌");
} }
log.info("jwtExpiration毫秒值:{}",jwtExpiration);
AuthUserDto authUserDto = (AuthUserDto) authentication.getPrincipal(); AuthUserDto authUserDto = (AuthUserDto) authentication.getPrincipal();
try { try {
...@@ -185,7 +185,7 @@ public class JwtTokenProvider { ...@@ -185,7 +185,7 @@ public class JwtTokenProvider {
} }
} }
public int getJwtExpiration() { public long getJwtExpiration() {
return jwtExpiration; return jwtExpiration;
} }
...@@ -220,10 +220,117 @@ public class JwtTokenProvider { ...@@ -220,10 +220,117 @@ public class JwtTokenProvider {
.getHeader(); .getHeader();
} }
// 在 JwtTokenProvider 类中添加以下方法
/**
* 解析 JWT token 并获取过期时间
* 这个方法不需要 Spring 依赖注入,可以直接调用
*/
public static void analyzeToken(String token, String secretKey) {
try {
// 使用给定的密钥进行解析
byte[] keyBytes = Base64.getDecoder().decode(secretKey);
SecretKey key = Keys.hmacShaKeyFor(keyBytes);
// 解析 token
Jws<Claims> claimsJws = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token);
Claims claims = claimsJws.getBody();
System.out.println("Token 解析成功:");
System.out.println("Subject (用户ID): " + claims.getSubject());
System.out.println("Issued At (签发时间): " + new Date(claims.getIssuedAt().getTime()));
System.out.println("Expiration (过期时间): " + new Date(claims.getExpiration().getTime()));
System.out.println("Roles: " + claims.get("roles"));
// 计算剩余有效期
long currentTime = System.currentTimeMillis();
long expirationTime = claims.getExpiration().getTime();
long remainingTime = expirationTime - currentTime;
System.out.println("当前时间: " + new Date(currentTime));
System.out.println("距离过期还有: " + formatDuration(remainingTime));
} catch (ExpiredJwtException e) {
// 即使过期了,也能获取到 claims
Claims claims = e.getClaims();
System.out.println("Token 已过期:");
System.out.println("Subject (用户ID): " + claims.getSubject());
System.out.println("Issued At (签发时间): " + new Date(claims.getIssuedAt().getTime()));
System.out.println("Expiration (过期时间): " + new Date(claims.getExpiration().getTime()));
System.out.println("过期于: " + formatDuration(System.currentTimeMillis() - claims.getExpiration().getTime()) + "前");
} catch (Exception e) {
System.err.println("解析 Token 失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 格式化时间间隔
*/
private static String formatDuration(long millis) {
if (millis < 0) {
return "已过期 " + formatDuration(-millis);
}
long seconds = millis / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
if (days > 0) {
return days + "天 " + (hours % 24) + "小时";
} else if (hours > 0) {
return hours + "小时 " + (minutes % 60) + "分钟";
} else if (minutes > 0) {
return minutes + "分钟 " + (seconds % 60) + "秒";
} else {
return seconds + "秒";
}
}
/**
* 修改 main 方法,使用配置文件中的密钥
*/
public static void main(String[] args) { public static void main(String[] args) {
// 生成一个符合HS512要求的密钥 // 使用配置文件中的密钥
System.out.println("请将以下生成的JWT密钥复制到配置文件中(application.yml或application.properties):"); String configSecret = "v92cuMDOZEd0WIbmX9LHQpZ0HgMIfRPXvDXGmP+5ThbADd2YdD0mCbGujIvLSBZR2ZWby8PKYRT2ReBQ7wIDPQ==";
System.out.println("jwt.secret: " + generateSecureKey());
System.out.println("jwt.expiration: 86400000 # 24小时"); // 要解析的 token
String token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VyXzEwMDEiLCJyb2xlcyI6W10sImlhdCI6MTc2ODU2MjQwMSwiZXhwIjozMzQ2NDEwMDAxfQ.izMcWJfmhgi3rpyHn1_fNTbSYjWQMAjRN21hNWTBsbp84tsJSWaYew2Zr_dyyKf3woKoH_QsQ74FZl4gAs7Fug";
// 分析 token
System.out.println("使用配置文件中的密钥分析 Token:");
analyzeToken(token, configSecret);
System.out.println("\n--- 生成新的测试 Token ---");
// 使用配置文件中的密钥生成一个新的测试 token
try {
byte[] keyBytes = Base64.getDecoder().decode(configSecret);
SecretKey key = Keys.hmacShaKeyFor(keyBytes);
// 生成一个有效期更合理的测试 token(24小时)
long expiration = 1577847600000L; // 24小时
String newToken = Jwts.builder()
.setSubject("test_user_001")
.claim("roles", Arrays.asList("ROLE_USER"))
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(key, SignatureAlgorithm.HS512)
.compact();
System.out.println("新生成的 Token: " + newToken);
System.out.println("\n解析新生成的 Token:");
analyzeToken(newToken, configSecret);
} catch (Exception e) {
System.err.println("生成测试 Token 失败: " + e.getMessage());
}
} }
} }
...@@ -44,4 +44,29 @@ public class CodeGeneratorConstants { ...@@ -44,4 +44,29 @@ public class CodeGeneratorConstants {
* 保单发佣批次ID前缀 * 保单发佣批次ID前缀
*/ */
public static final String PREFIX_FORTUNE_BATCH_BIZ_ID = "FORTUNE_BATCH"; public static final String PREFIX_FORTUNE_BATCH_BIZ_ID = "FORTUNE_BATCH";
/**
* 分类编码前缀
*/
public static final String PREFIX_CATEGORY_CODE = "CATEGORY";
/**
* 字段编码前缀
*/
public static final String PREFIX_FIELD_CODE = "FIELD";
/**
* 字段值编码前缀
*/
public static final String PREFIX_FIELD_VALUE_CODE = "FIELD_VALUE";
/**
* 规格类型编码前缀
*/
public static final String PREFIX_SPECIES_TYPE_CODE = "SPECIES_TYPE_CODE";
/**
* 产品编码前缀
*/
public static final String PREFIX_PRODUCT_CODE = "PRODUCT_CODE";
} }
...@@ -14,4 +14,9 @@ public class RedisConstants { ...@@ -14,4 +14,9 @@ public class RedisConstants {
* 字典数据项列表的缓存信息redis前缀 * 字典数据项列表的缓存信息redis前缀
*/ */
public static final String DICT_LIST = "dict:list:"; public static final String DICT_LIST = "dict:list:";
/**
* 生成预计发佣的缓存信息redis前缀
*/
public static final String EXPECTED_FORTUNE = "expected:fortune:";
} }
...@@ -59,4 +59,14 @@ public class ServerNameConstants { ...@@ -59,4 +59,14 @@ public class ServerNameConstants {
* yd-csf-wx-api 香港保险服务接口模块服务名称-小程序端服务 * yd-csf-wx-api 香港保险服务接口模块服务名称-小程序端服务
*/ */
public static String ydCsfWxApi="yd-csf-wx-api"; public static String ydCsfWxApi="yd-csf-wx-api";
/**
* yd-product-api 产品微服务
*/
public static String ydProductApi="yd-product-api";
/**
* yd-base-api 基础数据微服务
*/
public static String ydBaseApi="yd-base-api";
} }
...@@ -30,6 +30,7 @@ public enum CommonEnum { ...@@ -30,6 +30,7 @@ public enum CommonEnum {
UID_TYPE_POLICY("policy","CSF保单表"), UID_TYPE_POLICY("policy","CSF保单表"),
UID_TYPE_COMMISSION("commission","CSF来佣表"), UID_TYPE_COMMISSION("commission","CSF来佣表"),
UID_TYPE_FORTUNE("fortune","CSF发佣表"), UID_TYPE_FORTUNE("fortune","CSF发佣表"),
UID_TYPE_EXPECTED_FORTUNE("expected_fortune","预计发佣表"),
UID_TYPE_EMAIL_SENDER_CONFIG("email_sender_config","邮箱发件人配置表"), UID_TYPE_EMAIL_SENDER_CONFIG("email_sender_config","邮箱发件人配置表"),
UID_TYPE_EMAIL_CONTACT("email_contact","邮箱联系人(收件人)表"), UID_TYPE_EMAIL_CONTACT("email_contact","邮箱联系人(收件人)表"),
UID_TYPE_EMAIL_PROVIDER_CONFIG("email_provider_config","SMTP邮箱服务商配置表"), UID_TYPE_EMAIL_PROVIDER_CONFIG("email_provider_config","SMTP邮箱服务商配置表"),
...@@ -46,6 +47,34 @@ public enum CommonEnum { ...@@ -46,6 +47,34 @@ public enum CommonEnum {
UID_TYPE_CONDITION_TYPE("condition_type","条件类型表"), UID_TYPE_CONDITION_TYPE("condition_type","条件类型表"),
UID_TYPE_CLIENT_USER("client_user","客户端用户表"), UID_TYPE_CLIENT_USER("client_user","客户端用户表"),
UID_TYPE_AGENT_REFERRAL_RELATION("agent_referral_relation","推荐关系表"), UID_TYPE_AGENT_REFERRAL_RELATION("agent_referral_relation","推荐关系表"),
UID_TYPE_CATEGORY("category","分类表"),
UID_TYPE_FIELD("field","字段表"),
UID_TYPE_FIELD_VALUE("field_value","字段值表"),
UID_TYPE_SPECIES("species","规格表"),
UID_TYPE_SPECIES_TYPE("species_type","规格类型表"),
UID_TYPE_PRODUCT("product","产品基础信息表"),
UID_TYPE_PRODUCT_LAUNCH("product_launch","产品上架信息表"),
UID_TYPE_ATTRIBUTE_SETTING("attribute_setting","上架产品属性(参数)配置表"),
UID_TYPE_SPECIES_SETTING("species_setting","上架产品规格配置表"),
UID_TYPE_SPECIES_PRICE("species_price","上架产品规格价格维护表"),
UID_TYPE_ANNOUNCEMENT_SPECIES("announcement_species","公告佣比率规格表"),
UID_TYPE_ANNOUNCEMENT_COMMISSION_RATIO("announcement_commission_ratio","公告佣比率规格明细表"),
UID_TYPE_EXPECTED_SPECIES("expected_species","来佣比率规格表"),
UID_TYPE_EXPECTED_COMMISSION_RATIO("expected_commission_ratio","来佣比率规格明细表"),
UID_TYPE_APPOINTMENT_REFERRER("appointment_referrer","预约-转介人信息表"),
UID_TYPE_APPOINTMENT_LOG("appointment_log","预约信息日志表"),
UID_TYPE_APPOINTMENT_REFERRER_LOG("appointment_referrer_log","预约-转介人信息日志表"),
UID_TYPE_APPOINTMENT_USER_SIGN("appointment_user_sign","预约-签单员信息表"),
UID_TYPE_APPOINTMENT_USER_SIGN_LOG("appointment_user_sign_log","预约-签单员信息日志表"),
UID_TYPE_REL_OBJECT_MATERIAL("rel_object_material","对象材料关系表"),
UID_TYPE_USER_SIGN_EXPAND("user_sign_expand","系统用户-签单用户扩展表"),
UID_TYPE_USER_SALE_EXPAND("user_sale_expand","系统用户-销售用户扩展表"),
UID_TYPE_TAXATION("taxation","税务信息表"),
UID_TYPE_INSURANCE_COMPANY("insurance_company","保险公司表"),
UID_TYPE_POLICY_RECEIPT("policy_receipt","保单回执表"),
UID_TYPE_PREMIUM_RECONCILIATION("premium_reconciliation","保费对账记录表"),
UID_TYPE_PREMIUM_REMITTANCE("premium_remittance","保费对账-汇款记录表"),
UID_TYPE_PREMIUM_REMITTANCE_FILE("premium_remittance_file","保费对账-汇款记录附件表"),
//作用域枚举 //作用域枚举
SCOPE_SYS("1","系统级(全局)"), SCOPE_SYS("1","系统级(全局)"),
......
...@@ -38,6 +38,17 @@ public class Result<T> implements Serializable { ...@@ -38,6 +38,17 @@ public class Result<T> implements Serializable {
} }
/** /**
* 成功返回(带上data和msg)
*/
public static <T> Result<T> success(T data,String msg) {
Result<T> result = new Result<T>();
result.setCode(200);
result.setMsg(msg);
result.setData(data);
return result;
}
/**
* 失败返回 * 失败返回
*/ */
public static <T> Result<T> fail(int code, String msg) { public static <T> Result<T> fail(int code, String msg) {
......
...@@ -89,8 +89,8 @@ public class CodeGenerator { ...@@ -89,8 +89,8 @@ public class CodeGenerator {
} }
public static void main(String[] args) { public static void main(String[] args) {
for (int i = 0; i < 5; i++) { for (int i = 0; i < 6; i++) {
System.out.println(generate10Code("CONDITION")); System.out.println(generate10Code("FIELD_VALUE"));
} }
} }
......
package com.yd.common.utils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText();
if (text == null || text.isEmpty()) {
return null;
}
// 如果字符串长度只有10(即"yyyy-MM-dd"),则拼接" 00:00:00"
if (text.length() == 10) {
text = text + " 00:00:00";
}
return LocalDateTime.parse(text, DATE_TIME_FORMATTER);
}
}
\ No newline at end of file
...@@ -125,8 +125,24 @@ public class DateUtil { ...@@ -125,8 +125,24 @@ public class DateUtil {
} }
} }
public static String yyMMdd(String timeStr){
try {
// 定义输入格式
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date date = inputFormat.parse(timeStr);
// 定义输出格式
SimpleDateFormat outputFormat = new SimpleDateFormat("yyMMdd");
String result = outputFormat.format(date);
return result;
} catch (Exception e) {
return "";
}
}
public static void main(String[] args) { public static void main(String[] args) {
System.out.println(getHHmm(LocalDateTime.now())); System.out.println(yyMMdd("2025-02-20 11:30"));
} }
/** /**
......
...@@ -60,8 +60,8 @@ public class RandomStringGenerator { ...@@ -60,8 +60,8 @@ public class RandomStringGenerator {
// String random32 = generate(32, false); // String random32 = generate(32, false);
// System.out.println("32位: " + random32); // System.out.println("32位: " + random32);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 6; i++) {
System.out.println(generateBizId16("agent_referral_relation")); System.out.println(generateBizId16("client_user"));
} }
} }
......
package com.yd.common.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
public class TokenUtils {
/**
* 获取当前请求的token
* @return
*/
public static String getCurrentToken() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 从Header中获取token
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
return token;
}
// 从参数中获取token
token = request.getHeader("token");
if (token != null) {
return token;
}
}
return null;
}
}
\ No newline at end of file
...@@ -13,8 +13,20 @@ import javax.servlet.http.HttpServletRequest; ...@@ -13,8 +13,20 @@ import javax.servlet.http.HttpServletRequest;
public class FeignTokenInterceptor implements RequestInterceptor { public class FeignTokenInterceptor implements RequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(FeignTokenInterceptor.class); private static final Logger logger = LoggerFactory.getLogger(FeignTokenInterceptor.class);
// 使用ThreadLocal存储Token,用于异步场景
private static final ThreadLocal<String> THREAD_LOCAL_TOKEN = new ThreadLocal<>();
@Override @Override
public void apply(RequestTemplate template) { public void apply(RequestTemplate template) {
// 首先尝试从ThreadLocal获取(异步场景)
String threadLocalToken = THREAD_LOCAL_TOKEN.get();
if (threadLocalToken != null && !threadLocalToken.trim().isEmpty()) {
template.header("Authorization", threadLocalToken);
logger.debug("从ThreadLocal添加Authorization头到Feign请求");
return;
}
// ThreadLocal没有,再从请求上下文获取(同步场景)
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) { if (attributes == null) {
...@@ -32,4 +44,14 @@ public class FeignTokenInterceptor implements RequestInterceptor { ...@@ -32,4 +44,14 @@ public class FeignTokenInterceptor implements RequestInterceptor {
logger.debug("当前请求中没有Authorization头,跳过Token传递"); logger.debug("当前请求中没有Authorization头,跳过Token传递");
} }
} }
// 设置ThreadLocal Token的方法
public static void setThreadLocalToken(String token) {
THREAD_LOCAL_TOKEN.set(token);
}
// 清理ThreadLocal Token的方法
public static void clearThreadLocalToken() {
THREAD_LOCAL_TOKEN.remove();
}
} }
...@@ -6,7 +6,7 @@ LABEL maintainer="zxm<2060197959@qq.com>" ...@@ -6,7 +6,7 @@ LABEL maintainer="zxm<2060197959@qq.com>"
RUN mkdir -p /home/app RUN mkdir -p /home/app
# 拷贝项目jar - 使用可执行的 fat JAR # 拷贝项目jar - 使用可执行的 fat JAR
COPY target/yd-gateway-1.0-SNAPSHOT-exec.jar /home/app/yd-gateway.jar COPY target/yd-gateway-1.0-SNAPSHOT-exec.jar /home/app/yd-gateway.jar
# 执行命令启动jar # 执行命令启动jar,并设置JVM内存参数
ENTRYPOINT ["java", "-jar", "/home/app/yd-gateway.jar"] ENTRYPOINT ["java", "-Xmx256m", "-Xms128m", "-jar", "/home/app/yd-gateway.jar"]
# 暴露端口 # 暴露端口
EXPOSE 9002 EXPOSE 9002
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment