فهرست منبع

增加风控规则 同应用不允许x天内不允许用户注册多渠道

marxjaw 4 ماه پیش
والد
کامیت
a5babb5db8

+ 2 - 0
yt-agent/agent-service/src/main/java/com/ytpm/service/impl/YtAppUserServiceImpl.java

@@ -99,6 +99,8 @@ public class YtAppUserServiceImpl implements YtAppUserService {
                 datum.setAppType(ytApp.getAppType());
                 datum.setChannelId(ytApp.getChannelId());
                 datum.setVersionCode(ytApp.getVersionCode());
+                datum.setDitchId(ytApp.getDitchId());
+                datum.setDitchName(ytApp.getDitchName());
             }
             if(CollUtil.isNotEmpty(recordList)){
                 datum.setDeviceRepeatCount((int) recordList.stream().map(YtDyzLoginRecord::getDeviceModel).distinct().count());

+ 3 - 3
yt-agent/agent-service/src/main/resources/mapper/AppMapper.xml

@@ -130,20 +130,20 @@
     </delete>
     <select id="selectPrimary" resultType="com.ytpm.agent.model.YtApp">
         select
-            app_id, app_key, app_name,user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled
+            app_id,ditch_id, ditch_name,  app_key, app_name,user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled
         from yt_app
         where app_id = #{appId}
     </select>
     <select id="queryAll" resultType="com.ytpm.agent.model.YtApp">
         select
-            app_id, app_key, app_name, user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled, store_on_sale, store_type, store_url, package_name, domain, category, sub_category, coppa, screen_orientation, ccpa
+            app_id, ditch_id, ditch_name, app_key, app_name, user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled, store_on_sale, store_type, store_url, package_name, domain, category, sub_category, coppa, screen_orientation, ccpa
         from yt_app
         where user_id = #{userId}
     </select>
 
     <select id="selectByDitchId" resultType="com.ytpm.agent.model.YtApp">
         select
-            app_id, app_key, app_name,user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled,ditch_name,ditch_id
+            app_id, ditch_id, ditch_name, app_key, app_name,user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled,ditch_name,ditch_id
         from yt_app
         where ditch_id = #{ditchId}
     </select>

+ 2 - 0
yt-app/app-feign/src/main/java/com/ytpm/feign/AppFeign.java

@@ -42,4 +42,6 @@ public interface AppFeign {
     @PostMapping("/user/queryLoginRecords")
      List<String> queryLoginRecords(@RequestBody AppUserQueryParam appUserQueryParam);
 
+    @GetMapping("/user/queryByOpenid")
+    List<YtDyzUser> queryByOpenid(@RequestParam("openid") String openid);
 }

+ 5 - 0
yt-app/app-service/src/main/java/com/ytpm/controller/UserController.java

@@ -240,4 +240,9 @@ public class UserController {
     public List<String> queryLoginRecords(@RequestBody AppUserQueryParam appUserQueryParam) {
         return loginRecordMapper.queryLoginCount(appUserQueryParam);
     }
+
+    @GetMapping("/user/queryByOpenid")
+    public List<YtDyzUser> queryByOpenid(@RequestParam("openid") String openid){
+        return appUserMapper.queryByOpenid(openid);
+    }
 }

+ 2 - 0
yt-app/app-service/src/main/java/com/ytpm/dao/AppUserMapper.java

@@ -77,4 +77,6 @@ public interface AppUserMapper {
      * 根据应用ID获取应用secret
      */
     String getSecretByAppId(@Param("appId") String appId);
+
+    List<YtDyzUser> queryByOpenid(@Param("openid")String openid);
 }

+ 14 - 3
yt-app/app-service/src/main/resources/mapper/AppUserMapper.xml

@@ -181,9 +181,14 @@
     </select>
     <select id="getUserList" resultType="com.ytpm.app.model.YtDyzUser">
         select
-            user_id,app_id, ditch_id, head_img, nick_name, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, platform_id, power
-        from yt_dyz_user
-        where user_id in
+            du.user_id,
+            head_img,
+            nick_name,
+            registry_time,
+            last_login_time,
+            last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, ditch_id, app_id, platform_id, power
+        from yt_dyz_user du
+        where du.user_id in
         <foreach collection="userIds.split(',')" item="item" separator="," open="(" close=")">
             #{item}
         </foreach>
@@ -219,4 +224,10 @@
         from yt_app_default_config
         where app_id = #{appId}
     </select>
+    <select id="queryByOpenid" resultType="com.ytpm.app.model.YtDyzUser">
+        select
+            user_id, head_img, nick_name, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, ditch_id, app_id, platform_id, power
+        from yt_dyz_user
+        where wx_open_id = #{openid}
+    </select>
 </mapper>

+ 10 - 1
yt-common/src/main/java/com/ytpm/app/model/DefaultRiskConfig.java

@@ -17,7 +17,7 @@ import java.math.BigDecimal;
 @AllArgsConstructor
 @NoArgsConstructor
 public class DefaultRiskConfig {
-    @CustomField(desc = "?天内",node = 1)
+    @CustomField(desc = "?天内",node = 99)
     @ApiModelProperty("?天内")
     private int days;
     @CustomField(desc = "IP前?段",node = 1)
@@ -44,4 +44,13 @@ public class DefaultRiskConfig {
     @ApiModelProperty("有?条")
     private int haveCount;
 
+    @CustomField(desc = "生成UID数", node = 1)
+    @ApiModelProperty("生成UID数")
+    private int uidCount;
+    /**
+     * 校验的字段名,用于匹配数据中相同字段
+     */
+    @CustomField(value = "same_field_name", desc = "字段?相同", node = 99)
+    @ApiModelProperty("字段?相同")
+    private String sameFieldName;
 }

+ 2 - 0
yt-common/src/main/java/com/ytpm/app/model/YtDyzUser.java

@@ -111,6 +111,8 @@ public class YtDyzUser extends PageMeta {
     private int todayVideo;
     @ApiModelProperty(value = "渠道ID")
     private Long ditchId;
+    @ApiModelProperty(value = "渠道名称")
+    private String ditchName;
     @ApiModelProperty(value = "今日收益")
     private BigDecimal todayIncome;
     @ApiModelProperty(value = "应用ID")

+ 4 - 0
yt-common/src/main/java/com/ytpm/app/view/YtAppUserListView.java

@@ -28,6 +28,10 @@ public class YtAppUserListView extends PageMeta {
     private String wxOpenId;
     @ApiModelProperty("渠道商ID")
     private String channelId;
+    @ApiModelProperty("渠道ID")
+    private Long ditchId;
+    @ApiModelProperty("渠道名称")
+    private String ditchName;
     @ApiModelProperty("平台ID")
     private String platformId;
     @ApiModelProperty("应用名称")

+ 1 - 1
yt-common/src/main/java/com/ytpm/custom/CustomField.java

@@ -9,7 +9,7 @@ import java.lang.annotation.Target;
 @Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface CustomField {
-    /** 注解携带值 */
+    /** 注解携带字典值 */
     String value() default "";
     /** 注解字段描述 */
     String desc() default "";

+ 18 - 0
yt-common/src/main/java/com/ytpm/risk/enums/EffectNodeEnum.java

@@ -0,0 +1,18 @@
+package com.ytpm.risk.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum EffectNodeEnum {
+    LOGIN(1,"登录"),
+    ADSOURCE(2, "广告"),
+    ;
+
+    private final Integer node;
+    private final String desc;
+
+    EffectNodeEnum(Integer node, String desc) {
+        this.node = node;
+        this.desc = desc;
+    }
+}

+ 7 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/dao/RiskConfigMapper.java

@@ -79,4 +79,11 @@ public interface RiskConfigMapper {
      * 根据effect_node 获取不同业务节点风控规则
      */
     RiskTemplateView getByNode(@Param("effectNode") Integer effectNode);
+
+    /**
+     * 根据应用ID查询用户自定义的风控配置模版
+     * @param appId 应用ID
+     * @param effectNode 业务节点
+     */
+    List<RiskTemplateView> getCustomTempConfig(@Param("appId") String appId,@Param("effectNode")Integer effectNode);
 }

+ 99 - 17
yt-risk/risk-manage/src/main/java/com/ytpm/service/impl/RiskServiceImpl.java

@@ -2,6 +2,7 @@ package com.ytpm.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateUnit;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.text.CharSequenceUtil;
 import cn.hutool.core.util.IdUtil;
@@ -30,6 +31,7 @@ import com.ytpm.general.Result;
 import com.ytpm.general.ResultTable;
 import com.ytpm.handle.CustomerException;
 import com.ytpm.risk.enums.BannedTypeEnum;
+import com.ytpm.risk.enums.EffectNodeEnum;
 import com.ytpm.risk.model.YtRiskConfig;
 import com.ytpm.risk.model.YtRiskTemplate;
 import com.ytpm.risk.param.RiskBannedListParam;
@@ -66,6 +68,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -95,7 +98,7 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
     @Override
     public ResultTable<RiskConfigView> getRiskConfig(String appIds) {
         List<AgentAppClassView> viewList = configMapper.getAppClazz(appIds);
-        List<RiskConfigView> configList = new ArrayList<RiskConfigView>();
+        List<RiskConfigView> configList = new ArrayList<>();
         try{
             for (AgentAppClassView view : viewList) {
                 addConfigItem(Class.forName(view.getFullName()).getDeclaredFields(),configList,null);
@@ -113,10 +116,11 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
     @Override
     public ResultTable<RiskConfigView> getFieldConfigByNode(Integer effectNode) {
         List<AgentAppClassView> viewList = configMapper.getAppClazz("");
-        List<RiskConfigView> configList = new ArrayList<RiskConfigView>();
+        List<RiskConfigView> configList = new ArrayList<>();
+        Set<String> clazzSet = viewList.stream().map(AgentAppClassView::getFullName).collect(Collectors.toSet());
         try{
-            for (AgentAppClassView view : viewList) {
-                addConfigItem(Class.forName(view.getFullName()).getDeclaredFields(),configList,effectNode);
+            for (String fullName : clazzSet) {
+                addConfigItem(Class.forName(fullName).getDeclaredFields(),configList,effectNode);
             }
         }catch (Exception e){
             log.error(e.getMessage());
@@ -132,8 +136,10 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         RiskConfigView view;
         for (Field field : fields) {
             field.setAccessible(true);
-            if(Objects.nonNull(effectNode) && field.getAnnotation(CustomField.class).node() != effectNode)continue;
-            if(!field.isAnnotationPresent(CustomField.class))continue;
+            if((Objects.nonNull(effectNode) && field.getAnnotation(CustomField.class).node()!=99 &&
+                    field.getAnnotation(CustomField.class).node() != effectNode)||
+                    !field.isAnnotationPresent(CustomField.class)
+            )continue;
             view = new RiskConfigView();
             view.setFieldName(field.getName());
             if(CharSequenceUtil.isNotBlank(field.getAnnotation(CustomField.class).value())){
@@ -163,8 +169,11 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
             BeanUtil.copyProperties(listVO, config);
             config.setChannelId(param.getChannelId());
             String format = String.format(config.getFieldDesc(), config.getConfigVal());
-            if(CharSequenceUtil.isNotBlank(format)&&configList.indexOf(listVO)!= (configList.size() - 1)){
-                content.append(format).append(",");
+            if(CharSequenceUtil.isNotBlank(format)){
+                content.append(format);
+                if(configList.indexOf(listVO)!= (configList.size() - 1)){
+                    content.append(",");
+                }
             }
             configs.add(config);
         }
@@ -406,7 +415,7 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
             config.setConfigVal(listParam.getConfigVal());
             configMapper.updateConfigVal(config);
             String format = String.format(listParam.getFieldDesc(), listParam.getConfigVal());
-            if(StrUtil.isNotBlank(format)){
+            if(CharSequenceUtil.isNotBlank(format)){
                 content.append(format).append(",");
             }
         }
@@ -430,11 +439,39 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         if(1==view.getEnabled()){
             checkDefaultRiskConfig(dyzUser, view.getConfigList());
         }
+        checkRisk322(dyzUser);
         //查询用户所在app是否配置其他风控规则
-
+//        checkCustomRisk(dyzUser,EffectNodeEnum.LOGIN.getNode(),null);
         return Result.resultOk(RepMessage.QUERY_SUCCESS);
     }
 
+    /**
+     * 校验风控规则322
+     */
+    private void checkRisk322(YtDyzUser dyzUser) {
+        RiskTemplateView view = configMapper.getByCode("322");
+        //根据openid查询用户信息
+        List<YtDyzUser> dyzUsers = appFeign.queryByOpenid(dyzUser.getWxOpenId());
+        List<RiskConfigView> configList = view.getConfigList();
+        Map<String, String> configMap = configList.stream().collect(
+                Collectors.toMap(RiskConfigView::getFieldName, RiskConfigView::getConfigVal));
+        //判断同应用 UID生成数如果不小于配置数则触发规则校验
+        int uidCount = Integer.parseInt(configMap.get("uidCount"));
+        if(dyzUsers.size()<uidCount)return;
+        //获取配置天数以判断 同应用多渠道账号注册时间间隔不得低于配置时间
+        int days = Integer.parseInt(configMap.get("days"));
+        List<Date> regDateList = dyzUsers.stream().map(YtDyzUser::getRegistryTime).collect(Collectors.toList());
+        Date first = regDateList.get(0);
+        long interval;
+        for (int i = 1; i < regDateList.size(); i++) {
+            interval  = DateUtil.between(first, regDateList.get(i), DateUnit.DAY);
+            if(days > interval){
+                riskLockUser(dyzUser,"322","系统判定重复刷单用户限制","当前用户已被风控!");
+            }
+            first = regDateList.get(i);
+        }
+    }
+
     /**
      * 校验默认风控配置, 固定配置值不改
      *  days ?天内为1
@@ -505,9 +542,31 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         if(!records.isEmpty() && records.size()>1){
             checkRisk746(dyzUser,records);
         }
+        //查询用户所在app是否配置其他风控规则
+//        checkCustomRisk(dyzUser,EffectNodeEnum.ADSOURCE.getNode(),table.getData());
         return Result.resultOk(RepMessage.QUERY_SUCCESS);
     }
 
+    /**
+     * 校验用户自定义风控规则
+     */
+    private void checkCustomRisk(YtDyzUser dyzUser, Integer node, List<YtDyzAdRecord> data) {
+        List<RiskTemplateView> templateList = configMapper.getCustomTempConfig(
+                dyzUser.getAppId(), node);
+        if(CollUtil.isNotEmpty(templateList)){
+            //校验用户的其他规则配置
+            for (RiskTemplateView templateView : templateList) {
+                if(EffectNodeEnum.LOGIN.getNode().equals(node)){
+                    checkCondition(dyzUser, templateView);
+                }else{
+                    for (YtDyzAdRecord datum : data) {
+                        checkCondition(datum, templateView);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * 校验默认风控规则746
      */
@@ -604,6 +663,7 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         switch (param.getUserStatus()){
             case 2:
                 appUser.setRiskReason(param.getReason());
+                break;
             case 3: //增加封禁记录
                 RiskBannedParam bannedParam = new RiskBannedParam();
                 BeanUtil.copyProperties(param, bannedParam);
@@ -688,10 +748,15 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
             try{
                 //多选校验值包含 单选校验值相等
                 Object o = conditionField.get(obj);
-                if(2==vo.getMulty()){
-                    checkSameVal(o, vo.getConfigVal(), vo.getFieldDesc());
-                }else{
-                    checkContainsVal(o,vo.getConfigVal(), vo.getFieldDesc());
+                switch (vo.getMulty()){
+                    case 1:
+                        checkContainsVal(o,vo.getConfigVal(), vo.getFieldDesc());
+                        break;
+                    case 2:
+                        checkSameVal(o, vo.getConfigVal(), vo.getFieldDesc());
+                        break;
+                    default:
+                        checkCompareVal(o, vo.getConfigVal(),vo.getFieldDesc(),vo.getMulty());
                 }
             }catch (Exception e){
                 throw new CustomerException(e.getMessage());
@@ -700,6 +765,24 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
 
     }
 
+    /**
+     * 校验值大于
+     * @param o 校验对象值
+     * @param configVal 配置值
+     * @param fieldDesc 字段描述
+     * @param type 3- o > configVal  4- o < configVal
+     */
+    private void checkCompareVal(Object o, String configVal, String fieldDesc, int type) {
+        BigDecimal a = new BigDecimal(o.toString());
+        BigDecimal b = new BigDecimal(configVal);
+        if(type == 3 && a.compareTo(b) < 1){
+                throw new CustomerException(fieldDesc+"不符合准入条件!");
+        }
+        if(type == 4 && b.compareTo(a) < 1){
+                throw new CustomerException(fieldDesc+"不符合准入条件!");
+        }
+    }
+
     /**
      * 校验值包含
      */
@@ -736,7 +819,7 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         }
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         try {
-            if(o instanceof Date && !format.parse(configVal).equals((Date)o)){
+            if(o instanceof Date && !format.parse(configVal).equals(o)){
                 throw new CustomerException(desc+"不符合准入条件!");
             }
         } catch (ParseException e) {
@@ -746,7 +829,6 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
 
     @Override
     public List<YtPlatformBanned> queryBannedRecord(Date startTime, Date endTime) {
-        List<YtPlatformBanned> ytPlatformBanneds = riskManageMapper.queryBannedRecord(startTime, endTime);
-        return ytPlatformBanneds;
+        return riskManageMapper.queryBannedRecord(startTime, endTime);
     }
 }

+ 24 - 0
yt-risk/risk-manage/src/main/resources/mapper/RiskConfigMapper.xml

@@ -264,4 +264,28 @@
         from yt_app
         where app_id = #{appId}
     </select>
+    <select id="getCustomTempConfig" resultMap="RiskTemplateViewMap">
+        SELECT
+            rt.template_id,
+            rt.template_code,
+            rt.template_name,
+            rt.template_content,
+            rt.enabled,
+            rc.config_id,
+            rt.effect_node,
+            rc.field_name,
+            rc.field_desc,
+            rc.config_type,
+            rc.config_val,
+            rc.multy
+        FROM
+            yt_risk_template rt
+                LEFT JOIN yt_risk_template_config rtc ON rt.template_id = rtc.template_id
+                LEFT JOIN yt_risk_config rc ON rtc.config_id = rc.config_id
+        WHERE
+            rt.enabled = 1
+            and rt.can_modify = 1
+            and rt.app_id = #{appId}
+            and rt.effect_node = #{effectNode}
+    </select>
 </mapper>