refactor(signature): 重构了获取 appSecret 的方式,引入了 ApiSignatureSecretFetcher 接口,允许不同的服务实现获取 appSecret 的逻辑

pull/186/head
diaohang 2025-04-27 16:12:00 +08:00
parent fd34572c48
commit 4702d8ed74
5 changed files with 60 additions and 8 deletions

View File

@ -2,8 +2,11 @@ package cn.iocoder.yudao.framework.signature.config;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import cn.iocoder.yudao.framework.signature.core.aop.ApiSignatureAspect;
import cn.iocoder.yudao.framework.signature.core.fetcher.ApiSignatureSecretFetcher;
import cn.iocoder.yudao.framework.signature.core.fetcher.DefaultApiSignatureSecretFetcherImpl;
import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
@ -16,8 +19,9 @@ import org.springframework.data.redis.core.StringRedisTemplate;
public class YudaoApiSignatureAutoConfiguration {
@Bean
public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO) {
return new ApiSignatureAspect(signatureRedisDAO);
public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO,
ApiSignatureSecretFetcher apiSignatureSecretFetcher) {
return new ApiSignatureAspect(signatureRedisDAO, apiSignatureSecretFetcher);
}
@Bean
@ -25,4 +29,9 @@ public class YudaoApiSignatureAutoConfiguration {
return new ApiSignatureRedisDAO(stringRedisTemplate);
}
@Bean
@ConditionalOnMissingBean
public ApiSignatureSecretFetcher apiSignatureSecretFetcher(ApiSignatureRedisDAO apiSignatureRedisDAO) {
return new DefaultApiSignatureSecretFetcherImpl(apiSignatureRedisDAO);
}
}

View File

@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature;
import cn.iocoder.yudao.framework.signature.core.fetcher.ApiSignatureSecretFetcher;
import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
@ -36,6 +37,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
public class ApiSignatureAspect {
private final ApiSignatureRedisDAO signatureRedisDAO;
private final ApiSignatureSecretFetcher apiSignatureSecretFetcher;
@Before("@annotation(signature)")
public void beforePointCut(JoinPoint joinPoint, ApiSignature signature) {
@ -58,7 +60,7 @@ public class ApiSignatureAspect {
}
// 1.2 校验 appId 是否能获取到对应的 appSecret
String appId = request.getHeader(signature.appId());
String appSecret = signatureRedisDAO.getAppSecret(appId);
String appSecret = apiSignatureSecretFetcher.getAppSecret(appId);
Assert.notNull(appSecret, "[appId({})] 找不到对应的 appSecret", appId);
// 2. 校验签名【重要!】

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.framework.signature.core.fetcher;
/**
* Secret <br/>
* appSecret
*
* @author diaohang
*/
public interface ApiSignatureSecretFetcher {
/**
* appSecret
*
* @param appId appId
* @return appSecret
*/
String getAppSecret(String appId);
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.framework.signature.core.fetcher;
import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO;
import lombok.RequiredArgsConstructor;
/**
* @author diaohang
*/
@RequiredArgsConstructor
public class DefaultApiSignatureSecretFetcherImpl implements ApiSignatureSecretFetcher {
private final ApiSignatureRedisDAO apiSignatureRedisDAO;
@Override
public String getAppSecret(String appId) {
return apiSignatureRedisDAO.getAppSecret(appId);
}
}

View File

@ -5,6 +5,7 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature;
import cn.iocoder.yudao.framework.signature.core.aop.ApiSignatureAspect;
import cn.iocoder.yudao.framework.signature.core.fetcher.ApiSignatureSecretFetcher;
import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
@ -20,7 +21,8 @@ import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* {@link ApiSignatureTest}
@ -31,6 +33,9 @@ public class ApiSignatureTest {
@InjectMocks
private ApiSignatureAspect apiSignatureAspect;
@Mock
private ApiSignatureSecretFetcher apiSignatureSecretFetcher;
@Mock
private ApiSignatureRedisDAO signatureRedisDAO;
@ -57,12 +62,12 @@ public class ApiSignatureTest {
when(request.getHeader(eq("timestamp"))).thenReturn(String.valueOf(timestamp));
when(request.getHeader(eq("nonce"))).thenReturn(nonce);
when(request.getHeader(eq("sign"))).thenReturn(sign);
when(request.getParameterMap()).thenReturn(MapUtil.<String, String[]>builder()
.put("v1", new String[]{"k1"}).put("k1", new String[]{"v1"}).build());
when(request.getParameterMap()).thenReturn(
MapUtil.<String, String[]>builder().put("v1", new String[] {"k1"}).put("k1", new String[] {"v1"}).build());
when(request.getContentType()).thenReturn("application/json");
when(request.getReader()).thenReturn(new BufferedReader(new StringReader("test")));
// mock 方法
when(signatureRedisDAO.getAppSecret(eq(appId))).thenReturn(appSecret);
when(apiSignatureSecretFetcher.getAppSecret(eq(appId))).thenReturn(appSecret);
when(signatureRedisDAO.setNonce(eq(appId), eq(nonce), eq(120), eq(TimeUnit.SECONDS))).thenReturn(true);
// 调用