init
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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<>();
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user