Browse Source

新增阿里云用户昵称、头像合法性校验接口

Woody 3 tuần trước cách đây
mục cha
commit
e437536c37

+ 6 - 0
framework-aliyun/pom.xml

@@ -15,6 +15,7 @@
     <version>1.0.0-RELEASE</version>
 
     <properties>
+        <aliyun-green.version>2.20.0</aliyun-green.version>
         <aliyun-captcha.version>1.1.2</aliyun-captcha.version>
         <aliyun-dypnsapi.version>1.2.1</aliyun-dypnsapi.version>
         <framework-base.version>1.0.0-RELEASE</framework-base.version>
@@ -26,6 +27,11 @@
             <artifactId>framework-base</artifactId>
             <version>${framework-base.version}</version>
         </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>green20220302</artifactId>
+            <version>${aliyun-green.version}</version>
+        </dependency>
         <dependency>
             <groupId>com.aliyun</groupId>
             <artifactId>captcha20230305</artifactId>

+ 16 - 0
framework-aliyun/src/main/java/com/chelvc/framework/aliyun/AliyunHandler.java

@@ -15,6 +15,22 @@ public interface AliyunHandler {
      */
     String code2mobile(String token);
 
+    /**
+     * 校验用户头像是否合法
+     *
+     * @param url 头像地址
+     * @return 风险信息
+     */
+    Risk verifyAvatar(String url);
+
+    /**
+     * 校验用户昵称是否合法
+     *
+     * @param nickname 用户昵称
+     * @return 风险信息
+     */
+    Risk verifyNickname(String nickname);
+
     /**
      * 校验智能验证码
      *

+ 77 - 1
framework-aliyun/src/main/java/com/chelvc/framework/aliyun/DefaultAliyunHandler.java

@@ -1,14 +1,24 @@
 package com.chelvc.framework.aliyun;
 
+import java.util.Map;
 import java.util.Objects;
 
 import com.aliyun.captcha20230305.models.VerifyIntelligentCaptchaRequest;
 import com.aliyun.captcha20230305.models.VerifyIntelligentCaptchaResponse;
 import com.aliyun.dypnsapi20170525.models.GetMobileRequest;
 import com.aliyun.dypnsapi20170525.models.GetMobileResponse;
+import com.aliyun.green20220302.Client;
+import com.aliyun.green20220302.models.ImageModerationRequest;
+import com.aliyun.green20220302.models.ImageModerationResponse;
+import com.aliyun.green20220302.models.TextModerationRequest;
+import com.aliyun.green20220302.models.TextModerationResponse;
 import com.aliyun.teaopenapi.models.Config;
 import com.aliyun.teautil.models.RuntimeOptions;
 import com.chelvc.framework.aliyun.config.AliyunProperties;
+import com.chelvc.framework.common.util.JacksonUtils;
+import com.chelvc.framework.common.util.ObjectUtils;
+import com.chelvc.framework.common.util.StringUtils;
+import com.google.common.collect.ImmutableMap;
 import lombok.NonNull;
 import lombok.extern.slf4j.Slf4j;
 
@@ -21,15 +31,27 @@ import lombok.extern.slf4j.Slf4j;
 @Slf4j
 public class DefaultAliyunHandler implements AliyunHandler {
     private final AliyunProperties properties;
+    private final com.aliyun.green20220302.Client green;
     private final com.aliyun.captcha20230305.Client captcha;
     private final com.aliyun.dypnsapi20170525.Client dypnsapi;
+    private final RuntimeOptions runtime = new RuntimeOptions();
 
     public DefaultAliyunHandler(@NonNull AliyunProperties properties) {
         this.properties = properties;
+        this.runtime.readTimeout = 10000;
+        this.runtime.connectTimeout = 10000;
 
         try {
-            // 初始化captcha客户端
+            // 初始化green客户端
             Config config = this.getConfig(properties);
+            config.endpoint = "green-cip.cn-shanghai.aliyuncs.com";
+            config.setRegionId("cn-shanghai");
+            config.setReadTimeout(6000);
+            config.setConnectTimeout(3000);
+            this.green = new Client(config);
+
+            // 初始化captcha客户端
+            config = this.getConfig(properties);
             config.endpoint = "captcha.cn-shanghai.aliyuncs.com";
             this.captcha = new com.aliyun.captcha20230305.Client(config);
 
@@ -71,6 +93,60 @@ public class DefaultAliyunHandler implements AliyunHandler {
         return response.body.getGetMobileResultDTO().getMobile();
     }
 
+    @Override
+    public Risk verifyAvatar(@NonNull String url) {
+        ImageModerationRequest request = new ImageModerationRequest();
+        request.setService("profilePhotoCheck");
+        request.setServiceParameters(JacksonUtils.serialize(ImmutableMap.of("imageUrl", url)));
+        ImageModerationResponse response;
+        try {
+            response = this.green.imageModerationWithOptions(request, this.runtime);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        if (response == null || response.body == null) {
+            throw new RuntimeException("Invalid aliyun response");
+        }
+        if (response.body.code != 200) {
+            log.error("Aliyun avatar green verify failed: {}, {}", response.body.code, response.body.msg);
+            return Risk.builder().level(RiskLevel.NONE).build();
+        }
+        RiskLevel level = RiskLevel.valueOf(response.body.data.riskLevel.toUpperCase());
+        if (level != RiskLevel.NONE && ObjectUtils.notEmpty(response.body.data.result)) {
+            String description = response.body.data.result.get(0).getDescription();
+            return Risk.builder().level(level).description(description).build();
+        }
+        return Risk.builder().level(level).build();
+    }
+
+    @Override
+    public Risk verifyNickname(@NonNull String nickname) {
+        TextModerationRequest request = new TextModerationRequest();
+        request.setService("nickname_detection");
+        request.setServiceParameters(JacksonUtils.serialize(ImmutableMap.of("content", nickname)));
+        TextModerationResponse response;
+        try {
+            response = this.green.textModerationWithOptions(request, this.runtime);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        if (response == null || response.body == null) {
+            throw new RuntimeException("Invalid aliyun response");
+        }
+        if (response.body.code != 200) {
+            log.error("Aliyun nickname green verify failed: {}, {}", response.body.code, response.body.message);
+            return Risk.builder().level(RiskLevel.NONE).build();
+        }
+        if (StringUtils.notEmpty(response.body.data.reason)) {
+            Map<?, ?> reason = JacksonUtils.deserialize(response.body.data.reason, Map.class);
+            RiskLevel level = RiskLevel.valueOf(String.valueOf(reason.get("riskLevel")).toUpperCase());
+            if (level != RiskLevel.NONE) {
+                return Risk.builder().level(level).description(response.body.data.descriptions).build();
+            }
+        }
+        return Risk.builder().level(RiskLevel.NONE).build();
+    }
+
     @Override
     public boolean verifyCaptcha(@NonNull String verification) {
         VerifyIntelligentCaptchaRequest request = new VerifyIntelligentCaptchaRequest();

+ 30 - 0
framework-aliyun/src/main/java/com/chelvc/framework/aliyun/Risk.java

@@ -0,0 +1,30 @@
+package com.chelvc.framework.aliyun;
+
+import java.io.Serializable;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+
+/**
+ * 风险信息模型
+ *
+ * @author Woody
+ * @date 2025/5/12
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Risk implements Serializable {
+    /**
+     * 风险等级
+     */
+    private RiskLevel level;
+
+    /**
+     * 风险描述
+     */
+    private String description;
+}

+ 29 - 0
framework-aliyun/src/main/java/com/chelvc/framework/aliyun/RiskLevel.java

@@ -0,0 +1,29 @@
+package com.chelvc.framework.aliyun;
+
+/**
+ * 风险等级枚举
+ *
+ * @author Woody
+ * @date 2025/5/12
+ */
+public enum RiskLevel {
+    /**
+     * 高风险
+     */
+    HIGH,
+
+    /**
+     * 中风险
+     */
+    MEDIUM,
+
+    /**
+     * 低风险
+     */
+    LOW,
+
+    /**
+     * 无风险
+     */
+    NONE
+}