This commit is contained in:
ran.shang
2025-06-11 09:42:13 +08:00
commit 7e38b8d971
1935 changed files with 132836 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
package com.newyetai.sdk.captcha.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.newyetai.sdk.captcha.service.ITencentCaptchaService;
import com.newyetai.sdk.captcha.service.impl.LoginCaptchaAppProvider;
import com.newyetai.sdk.captcha.service.impl.TencentCaptchaServiceImpl;
import com.tencentcloudapi.common.Credential;
/**
* 验证码配置类
*
* @author sr on 2020-08-10
*/
@Configuration
@EnableConfigurationProperties({CaptchaProperties.class})
public class CaptchaConfiguration {
@Bean
@ConditionalOnProperty(havingValue = "true", name = "captcha.tencent.enable")
public ITencentCaptchaService tencentCaptchaService(CaptchaProperties captchaProperties) {
Credential credential = new Credential(captchaProperties.getTencent().getSecretId(),
captchaProperties.getTencent().getSecretKey());
return new TencentCaptchaServiceImpl(credential);
}
@Bean
@ConditionalOnBean(ITencentCaptchaService.class)
public LoginCaptchaAppProvider loginCaptchaAppProvider(
ITencentCaptchaService tencentCaptchaService, CaptchaProperties captchaProperties) {
return new LoginCaptchaAppProvider(tencentCaptchaService, captchaProperties);
}
}

View File

@@ -0,0 +1,23 @@
package com.newyetai.sdk.captcha.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 属性配置
*
* @author sr on 2020-08-10
*/
@ConfigurationProperties(prefix = CaptchaProperties.PREFIX)
@Data
@NoArgsConstructor
public class CaptchaProperties {
public static final String PREFIX = "captcha";
/** 腾讯配置 **/
private TencentProperties tencent;
}

View File

@@ -0,0 +1,18 @@
package com.newyetai.sdk.captcha.config;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 腾讯验证码应用配置
*
* @author sr on 2020-08-11
*/
@Data
@NoArgsConstructor
public class TencentAppProperties {
private String appId;
private String appSecret;
}

View File

@@ -0,0 +1,24 @@
package com.newyetai.sdk.captcha.config;
import java.util.HashMap;
import java.util.Map;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 腾讯配置
*
* @author sr on 2020-08-11
*/
@Data
@NoArgsConstructor
public class TencentProperties {
private Boolean enable;
private String secretId;
private String secretKey;
private final Map<String, TencentAppProperties> app = new HashMap<>();
}

View File

@@ -0,0 +1,57 @@
package com.newyetai.sdk.captcha.dto;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2020-08-10
*/
@Data
@NoArgsConstructor
public class TencentCaptchaDTO implements Serializable{
/** **/
private static final long serialVersionUID = 2301105027025640174L;
/** 前端回调函数返回的用户验证票据(必填) **/
@JsonProperty("Ticket")
private String ticket;
/** 用户操作来源的外网 IP(可为空,前提是上下文request不为空) **/
@JsonProperty("UserIp")
private String userIp;
/** 前端回调函数返回的随机字符串(必填) **/
@JsonProperty("Randstr")
private String randstr;
/** 验证码应用ID;(可为空,配置文件获取) **/
@JsonProperty("CaptchaAppId")
private Long captchaAppId;
/** 用于服务器端校验验证码票据的验证密钥;(可为空,配置文件获取) **/
@JsonProperty("AppSecretKey")
private String appSecretKey;
/** 业务 ID,网站或应用在多个业务中使用此服务,通过此 ID 区分统计数据(可为空) **/
@JsonProperty("BusinessId")
private Long businessId;
/** 场景 ID,网站或应用的业务下有多个场景使用此服务,通过此 ID 区分统计数据(可为空)**/
@JsonProperty("SceneId")
private Long sceneId;
/** mac 地址或设备唯一标识(可为空) **/
@JsonProperty("MacAddress")
private String macAddress;
/** 手机设备号(可为空) **/
@JsonProperty("Imei")
private String imei;
/** 是否返回前端获取验证码时间,取值1:需要返回(可为空) **/
@JsonProperty("NeedGetCaptchaTime")
private Long needGetCaptchaTime;
public TencentCaptchaDTO(String ticket, String randstr) {
super();
this.ticket = ticket;
this.randstr = randstr;
}
}

View File

@@ -0,0 +1,29 @@
package com.newyetai.sdk.captcha.mapstruct;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import com.newyetai.sdk.captcha.dto.TencentCaptchaDTO;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
/**
* @author sr on 2020-08-10
*/
@Mapper
public interface CaptchaRequestMapMapper {
CaptchaRequestMapMapper INSTANCE = Mappers.getMapper(CaptchaRequestMapMapper.class);
/**
* @param dto
* @return
* @author sr on 2020-08-10
*/
@Mappings({
@Mapping(target = "captchaType", constant = "9")
})
DescribeCaptchaResultRequest toRequest(TencentCaptchaDTO dto);
}

View File

@@ -0,0 +1,78 @@
package com.newyetai.sdk.captcha.service;
import org.apache.commons.lang3.StringUtils;
import com.newyetai.common.AlitaResult;
import com.newyetai.common.util.EnvironmentUtils;
import com.newyetai.common.util.RequestUtils;
import com.newyetai.common.util.SpringContextHolder;
import com.newyetai.sdk.captcha.config.CaptchaProperties;
import com.newyetai.sdk.captcha.dto.TencentCaptchaDTO;
import com.newyetai.sdk.captcha.mapstruct.CaptchaRequestMapMapper;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
import lombok.extern.slf4j.Slf4j;
/**
* @author sr on 2020-08-10
*/
@Slf4j
public abstract class AbstractTencentCaptchaAppProvider implements ITencentCaptchaAppProvider {
private static final String PARAM_NOT_ENOUTH = "参数缺失";
private ITencentCaptchaService tencentCaptchaService;
private String appIdKey;
private String appSecretKey;
private CaptchaProperties captchaProperties;
protected AbstractTencentCaptchaAppProvider(ITencentCaptchaService tencentCaptchaService,
CaptchaProperties captchaProperties) {
this.tencentCaptchaService = tencentCaptchaService;
this.captchaProperties = captchaProperties;
}
private String getAppIdKey() {
if (appIdKey == null) {
appIdKey = captchaProperties.getTencent().getApp().get(getAppType()).getAppId();
}
return appIdKey;
}
private String getAppSecretKey() {
if (appSecretKey == null) {
appSecretKey = captchaProperties.getTencent().getApp().get(getAppType()).getAppSecret();
}
return appSecretKey;
}
@Override
public AlitaResult<Boolean> verify(TencentCaptchaDTO tencentCaptchaDTO) {
try {
if (StringUtils.isBlank(tencentCaptchaDTO.getTicket()) || StringUtils.isBlank(tencentCaptchaDTO.getRandstr())) {
return AlitaResult.bizError(PARAM_NOT_ENOUTH);
}
DescribeCaptchaResultRequest request =
CaptchaRequestMapMapper.INSTANCE.toRequest(tencentCaptchaDTO);
// 用户ip
if (StringUtils.isBlank(request.getUserIp())) {
request.setUserIp(RequestUtils.getIpAddress(SpringContextHolder.getRequest()));
}
// 应用id secret
if (request.getCaptchaAppId() == null) {
request.setCaptchaAppId(Long.valueOf(EnvironmentUtils.getProperty(getAppIdKey())));
request.setAppSecretKey(EnvironmentUtils.getProperty(getAppSecretKey()));
}
return tencentCaptchaService.verify(request);
} catch (Exception e) {
log.error("tencent captcha verify error", e);
return AlitaResult.bizError("验证失败:{}" + e.getMessage());
}
}
public AlitaResult<Boolean> verify(String ticket, String randstr) {
TencentCaptchaDTO tencentCaptchaDTO = new TencentCaptchaDTO(ticket, randstr);
return this.verify(tencentCaptchaDTO);
}
}

View File

@@ -0,0 +1,23 @@
package com.newyetai.sdk.captcha.service;
import com.newyetai.common.AlitaResult;
import com.newyetai.sdk.captcha.dto.TencentCaptchaDTO;
/**
* @author sr on 2020-08-10
*/
public interface ITencentCaptchaAppProvider {
/**
* 验证应用类型;
* 同时确定应用id属性配置键
* id键:captcha.tencent.${appType}.appId,secret键:id键:captcha.tencent.${appType}.appSecret
*
* @return
* @author sr on 2020-08-10
*/
String getAppType();
AlitaResult<Boolean> verify(TencentCaptchaDTO tencentCaptchaDTO);
}

View File

@@ -0,0 +1,20 @@
package com.newyetai.sdk.captcha.service;
import com.newyetai.common.AlitaResult;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
/**
* @author sr on 2020-08-10
*/
public interface ITencentCaptchaService {
/**
* 验证
*
* @param request
* @return
* @author sr on 2020-08-10
*/
AlitaResult<Boolean> verify(DescribeCaptchaResultRequest request);
}

View File

@@ -0,0 +1,23 @@
package com.newyetai.sdk.captcha.service.impl;
import com.newyetai.sdk.captcha.config.CaptchaProperties;
import com.newyetai.sdk.captcha.service.AbstractTencentCaptchaAppProvider;
import com.newyetai.sdk.captcha.service.ITencentCaptchaService;
/**
* 登录防水墙
*
* @author sr on 2020-08-11
*/
public class LoginCaptchaAppProvider extends AbstractTencentCaptchaAppProvider {
public LoginCaptchaAppProvider(ITencentCaptchaService tencentCaptchaService, CaptchaProperties captchaProperties) {
super(tencentCaptchaService, captchaProperties);
}
@Override
public String getAppType() {
return "login";
}
}

View File

@@ -0,0 +1,55 @@
package com.newyetai.sdk.captcha.service.impl;
import org.apache.commons.lang3.StringUtils;
import com.newyetai.common.AlitaResult;
import com.newyetai.sdk.captcha.service.ITencentCaptchaService;
import com.tencentcloudapi.captcha.v20190722.CaptchaClient;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultResponse;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import lombok.extern.slf4j.Slf4j;
/**
* @author sr on 2020-08-10
*/
@Slf4j
public class TencentCaptchaServiceImpl implements ITencentCaptchaService {
private static final Long SUCCESS_CODE = 1L;
private Credential defaultCredential;
public TencentCaptchaServiceImpl(Credential defaultCredential) {
this.defaultCredential = defaultCredential;
}
@Override
public AlitaResult<Boolean> verify(DescribeCaptchaResultRequest request) {
try {
Credential cred = defaultCredential;
HttpProfile httpProfile = new HttpProfile();
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
CaptchaClient client = new CaptchaClient(cred, "", clientProfile);
log.info("tencent captcha request:{}", request);
DescribeCaptchaResultResponse resp = client.DescribeCaptchaResult(request);
log.info("tencent captcha response:{}", resp);
Long captchaCode = resp.getCaptchaCode();
if (SUCCESS_CODE.equals(captchaCode)) {
return AlitaResult.success(true);
}
String msg = resp.getCaptchaMsg();
return AlitaResult.success(StringUtils.isBlank(msg) ? captchaCode.toString() : msg, false);
} catch (TencentCloudSDKException e) {
log.info("tencent captcha error", e);
return AlitaResult.bizError(e.getMessage());
}
}
}