Forráskód Böngészése

chatgpt镜像当日风控

chenbiao 1 éve
szülő
commit
446bfe4808

+ 5 - 0
netflix-common/src/main/java/com/cyksj/dto/RedisKey.java

@@ -67,4 +67,9 @@ public class RedisKey {
      * 客服下标
      */
     public static String SERVICE_INDEX_KEY ="service_index_key";
+
+    /**
+     * 镜像gpt 当日使用量
+     */
+    public static String CHATGPT_USER_RESTRICTION ="chatgpt:user:restriction:";
 }

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/ChatgptUserRestrictionMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.ChatgptUserRestriction;
+
+/**
+ * @author chan
+ * @date 2024/12/26 15:35
+ */
+public interface ChatgptUserRestrictionMapper extends BaseMapper<ChatgptUserRestriction> {
+}

+ 29 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/ChatgptUserVerifyDto.java

@@ -0,0 +1,29 @@
+package com.cyksj.model.dto;
+
+import lombok.Data;
+
+/**
+ * @author chan
+ * @date 2024/12/26 16:20
+ */
+@Data
+public class ChatgptUserVerifyDto {
+
+    /**
+     * 用户凭证
+     */
+    private String userToken;
+
+    /**
+     * 验证id
+     */
+    private String restrictionId;
+
+    private String ticket;
+
+    private String randStr;
+
+    private String ip;
+
+    private String userAgent;
+}

+ 45 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/ChatgptUserRestriction.java

@@ -0,0 +1,45 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2024/12/26 15:33
+ */
+@Data
+public class ChatgptUserRestriction extends BaseEntity{
+
+    /**
+     *  风控id
+     */
+    private String restrictionId;
+
+    /**
+     * 用户凭证
+     */
+    private String userToken;
+
+    /**
+     * 是否解锁成功
+     */
+    private Boolean success;
+
+    /**
+     * 成功时间
+     */
+    private Date successTime;
+
+    /**
+     * 验证地址
+     */
+    private String url;
+
+    private String referer;
+
+    private String userAgent;
+
+    private String verifyUserAgent;
+
+}

+ 25 - 0
netflix-service/src/main/java/com/cyksj/service/chatgpt/ChatGptAccountService.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.chatgpt;
 
+import com.cyksj.model.dto.ChatgptUserVerifyDto;
 import com.cyksj.model.entity.ChatgptSession;
 import com.cyksj.model.entity.ChatgptUser;
 import com.cyksj.model.views.ChatGptUserView;
@@ -57,4 +58,28 @@ public interface ChatGptAccountService {
     void clearGptNum(Long relationId) throws Exception;
 
     void gptSwitchModel(long userId, Long relationId);
+
+    /**
+     * 风控检测
+     * @param userToken
+     * @param referer
+     * @param userAgent
+     * @return
+     */
+    String isRestrictions(String userToken, String referer, String userAgent);
+
+    /**
+     * 获取验证状态
+     * @param userToken
+     * @param restrictionId
+     * @return
+     */
+    Boolean gptRestrictionStatus(String userToken, String restrictionId);
+
+    /**
+     * 验证
+     * @param chatgptUserVerifyDto
+     * @return
+     */
+    Boolean verifyRestriction(ChatgptUserVerifyDto chatgptUserVerifyDto);
 }

+ 89 - 0
netflix-service/src/main/java/com/cyksj/service/chatgpt/impl/ChatGptAccountServiceImpl.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.chatgpt.impl;
 
+import cn.hutool.core.date.DateField;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUnit;
 import cn.hutool.core.date.DateUtil;
@@ -16,10 +17,14 @@ import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.snowflake.Sequence;
 import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.SmsUtil;
 import com.cyksj.common.util.StringUtil;
+import com.cyksj.dto.RedisKey;
 import com.cyksj.mapper.*;
 import com.cyksj.mapper.station.CollegeStudentStationUseTicketRecordMapper;
+import com.cyksj.model.dto.ChatgptUserVerifyDto;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.views.ChatGptUserView;
 import com.cyksj.model.views.ChatgptCarInfoView;
@@ -63,6 +68,9 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
 
     private static final String GPT_PROXY = "https://chat-chan-87jztgkf257d.xyhelper.org";
 
+    private static final String RESTRICTION_URL = "https://nf.video/bind/web/validating";
+
+    private final static Sequence SEQUENCE = new Sequence(0);
 
     private final RedisService redisService;
 
@@ -96,6 +104,8 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
 
     private final HttpServletRequest request;
 
+    private final ChatgptUserRestrictionMapper chatgptUserRestrictionMapper;
+
     @Override
     public String getGptSession(String account, String password) {
         String officialSession = "";
@@ -662,5 +672,84 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
         return DOMAIN;
     }
 
+    @Override
+    public String isRestrictions(String userToken, String referer, String userAgent) {
+        //从redis 中查询该usertoken 当日使用次数
+        DateTime now = DateTime.now();
+        DateTime dateTime = DateUtil.beginOfDay(now.toJdkDate());
+        DateTime endOfDayTime = DateUtil.endOfDay(now.toJdkDate());
+        DateTime twelveHoursAgo = DateUtil.offset(now, DateField.HOUR, -6);
+        ChatgptUserRestriction chatgptUserRestriction = chatgptUserRestrictionMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserRestriction.class)
+                .eq(ChatgptUserRestriction::getUserToken, userToken)
+                .ge(ChatgptUserRestriction::getCreatedTime, twelveHoursAgo.toString()).eq(ChatgptUserRestriction::getSuccess, false).last(" limit 1"));
+        if (chatgptUserRestriction != null) {
+            JSONObject result = new JSONObject();
+            result.putOpt("url",chatgptUserRestriction.getUrl());
+            result.putOpt("code",1);
+            return result.toString();
+        }
+        String numStr = redisService.getStr(RedisKey.CHATGPT_USER_RESTRICTION + userToken);
+        if (StringUtils.isNotBlank(numStr) && StringUtils.isNumeric(numStr)) {
+            long num = Long.parseLong(numStr);
+            if (num >= 150) {
+                //触发限制,需要人机验证
+                Integer count = chatgptUserRestrictionMapper.selectCount(Wrappers.lambdaQuery(ChatgptUserRestriction.class).eq(ChatgptUserRestriction::getUserToken, userToken)
+                        .ge(ChatgptUserRestriction::getCreatedTime, dateTime.toString()));
+                if (count > 10) {
+                    chatgptUserMapper.update(null, Wrappers.lambdaUpdate(ChatgptUser.class).eq(ChatgptUser::getUserToken, userToken).set(ChatgptUser::getIsBlock, 1));
+                }
+                ChatgptUserRestriction restriction = new ChatgptUserRestriction();
+
+                restriction.setRestrictionId(SEQUENCE.nextId().toString());
+                restriction.setUrl(RESTRICTION_URL + "?restrictionId=" + restriction.getRestrictionId() + "&token=" + userToken);
+                restriction.setUserToken(userToken);
+                restriction.setUserAgent(userAgent);
+                restriction.setReferer(referer);
+                chatgptUserRestrictionMapper.insert(restriction);
+                JSONObject result = new JSONObject();
+                result.putOpt("url",restriction.getUrl());
+                result.putOpt("code",1);
+                return result.toString();
+            }
+        }
+        JSONObject result = new JSONObject();
+        result.putOpt("code",0);
+        redisService.incr(RedisKey.CHATGPT_USER_RESTRICTION + userToken, 1L);
+        long between = DateUtil.between(now, endOfDayTime, DateUnit.SECOND, true);
+        redisService.expire(RedisKey.CHATGPT_USER_RESTRICTION + userToken, between);
+        return result.toString();
+    }
+
+    @Override
+    public Boolean gptRestrictionStatus(String userToken, String restrictionId) {
+        ChatgptUserRestriction chatgptUserRestriction = chatgptUserRestrictionMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserRestriction.class)
+                .eq(ChatgptUserRestriction::getUserToken, userToken)
+                .eq(ChatgptUserRestriction::getRestrictionId, restrictionId)
+                .last(" limit 1"));
+        if (chatgptUserRestriction == null) {
+            throw BusinessRuntimeException.getInstance("该验证异常.");
+        }else {
+            return chatgptUserRestriction.getSuccess();
+        }
+    }
+
+    @Override
+    public Boolean verifyRestriction(ChatgptUserVerifyDto chatgptUserVerifyDto) {
+        SmsUtil.checkTencentCaptcha(chatgptUserVerifyDto.getTicket(), chatgptUserVerifyDto.getIp(), chatgptUserVerifyDto.getRandStr());
+        // 清除一定次数,以及修改验证状态
+        ChatgptUserRestriction chatgptUserRestriction = chatgptUserRestrictionMapper.selectOne(Wrappers.lambdaQuery(ChatgptUserRestriction.class)
+                .eq(ChatgptUserRestriction::getUserToken, chatgptUserVerifyDto.getUserToken())
+                .eq(ChatgptUserRestriction::getRestrictionId, chatgptUserVerifyDto.getRestrictionId())
+                .eq(ChatgptUserRestriction::getSuccess, false)
+                .last(" limit 1"));
+        if (chatgptUserRestriction != null) {
+            chatgptUserRestriction.setSuccess(true);
+            chatgptUserRestriction.setVerifyUserAgent(chatgptUserVerifyDto.getUserAgent());
+            chatgptUserRestriction.setSuccessTime(new Date());
+            chatgptUserRestrictionMapper.updateById(chatgptUserRestriction);
+            redisService.decr(RedisKey.CHATGPT_USER_RESTRICTION + chatgptUserVerifyDto.getUserToken(), 50L);
+        }
+        return true;
+    }
 }
 

+ 53 - 0
netflix-web/src/main/java/com/cyksj/web/controller/mirror/MirrorController.java

@@ -3,6 +3,7 @@ package com.cyksj.web.controller.mirror;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.ServletUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -15,6 +16,7 @@ import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.GroupsMapper;
 import com.cyksj.mapper.GroupsRelationMapper;
 import com.cyksj.mapper.renew.RenewUpgradePackageMapper;
+import com.cyksj.model.dto.ChatgptUserVerifyDto;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.views.*;
 import com.cyksj.service.chatgpt.ChatGptAccountService;
@@ -29,6 +31,7 @@ import com.ejlchina.searcher.util.MapBuilder;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
 
@@ -418,4 +421,54 @@ public class MirrorController {
         LumaUser lumaUser = lumaService.getLumaUser(userId, relationId);
         return GatewayResponse.SUCCESS.newBuilder().toResult(lumaHost + (EnvCommonService.active_pre.equals(envCommonService.getEnv()) ? "/8083":"/8085") +"/api/applets/luma/lumaMirrorWithToken/" + lumaUser.getUserToken());
     }
+
+    /**
+     * gpt 次数风控
+     * @return
+     */
+    @GetMapping("/gpt/restrictions")
+    public String gptRestrictions(){
+        String authorization = request.getHeader("Authorization");
+        String referer = request.getHeader("Referer");
+        String userAgent = request.getHeader("User-Agent");
+        if (StringUtils.isBlank(authorization)) {
+            return "";
+        }
+        if (authorization.length() > 7) {
+            String userToken = authorization.substring(7);
+            return chatGptAccountService.isRestrictions(userToken,referer,userAgent);
+        }
+        return "";
+    }
+
+    /**
+     * 获取验证状态
+     * @return
+     */
+    @GetMapping("/gpt/restrictions/status")
+    public Result<Boolean> gptRestrictionStatus(String userToken, String restrictionId){
+        if (StringUtils.isAnyBlank(userToken, restrictionId)) {
+            throw BusinessRuntimeException.getInstance("缺少必填参数");
+        }
+        Boolean success = chatGptAccountService.gptRestrictionStatus(userToken, restrictionId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(success);
+    }
+
+    /**
+     * 验证
+     * @return
+     */
+    @PostMapping("/gpt/restrictions/verify")
+    public Result<Boolean> verifyRestriction(@RequestBody  ChatgptUserVerifyDto chatgptUserVerifyDto){
+        if (StringUtils.isAnyBlank(chatgptUserVerifyDto.getUserToken(), chatgptUserVerifyDto.getRestrictionId(),chatgptUserVerifyDto.getTicket(),chatgptUserVerifyDto.getRandStr())) {
+            throw BusinessRuntimeException.getInstance("缺少必填参数");
+        }
+        String ip = ServletUtil.getClientIP(request);
+        chatgptUserVerifyDto.setUserAgent(request.getHeader("User-Agent"));
+        chatgptUserVerifyDto.setIp(ip);
+        Boolean success = chatGptAccountService.verifyRestriction(chatgptUserVerifyDto);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(success);
+    }
+
+
 }