Explorar el Código

新增极光认证支持

Woody hace 1 mes
padre
commit
dc30f6cdca

+ 76 - 23
framework-jpush/src/main/java/com/chelvc/framework/jpush/DefaultJPushHandler.java

@@ -1,12 +1,20 @@
 package com.chelvc.framework.jpush;
 
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
+import javax.crypto.Cipher;
 
 import cn.jiguang.common.ServiceHelper;
 import cn.jiguang.common.resp.APIRequestException;
@@ -33,6 +41,7 @@ import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.jpush.config.JPushProperties;
 import com.chelvc.framework.jpush.context.JPushContextHolder;
+import com.google.common.collect.ImmutableMap;
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.extern.slf4j.Slf4j;
@@ -49,6 +58,11 @@ import org.springframework.http.MediaType;
  */
 @Slf4j
 public class DefaultJPushHandler implements JPushHandler {
+    /**
+     * 极光认证接口地址
+     */
+    private static final String CODE2MOBILE_URL = "https://api.verification.jpush.cn/v1/web/loginTokenVerify";
+
     /**
      * 获取消息地址
      */
@@ -75,6 +89,7 @@ public class DefaultJPushHandler implements JPushHandler {
     private final String appid;
     @Getter
     private final String authorization;
+    private final PrivateKey key;
     private final JPushClient pushClient;
     private final JMessageClient messageClient;
 
@@ -84,6 +99,17 @@ public class DefaultJPushHandler implements JPushHandler {
         this.messageClient = messageClient;
         this.appid = properties.getAppid();
         this.authorization = ServiceHelper.getBasicAuthorization(properties.getAppid(), properties.getSecret());
+
+        // 初始化私钥
+        this.key = StringUtils.ifEmpty(properties.getKey(), secret -> {
+            byte[] bytes = Base64.getDecoder().decode(secret);
+            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
+            try {
+                return KeyFactory.getInstance("RSA").generatePrivate(spec);
+            } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+                throw new RuntimeException(e);
+            }
+        });
     }
 
     /**
@@ -98,15 +124,62 @@ public class DefaultJPushHandler implements JPushHandler {
         headers.setContentType(MediaType.APPLICATION_JSON);
         HttpEntity<?> entity = new HttpEntity<>(headers);
         try {
-            return RestContextHolder.execute(rest -> rest.exchange(
-                    url, HttpMethod.GET, entity, ChatMessage.class
-            ).getBody());
+            return RestContextHolder.exchange(url, HttpMethod.GET, entity, ChatMessage.class);
         } catch (Exception e) {
             log.warn("JPush message get failed: {}, {}", url, e.getMessage());
             return null;
         }
     }
 
+    /**
+     * 获取消息投递结果
+     *
+     * @param ids 消息ID(多个ID之间使用","号隔开,最多最多支持 100 个消息ID)
+     * @return 投递结果列表
+     */
+    private List<ReceivedsResult.Received> getDeliveries(String ids) {
+        if (StringUtils.isEmpty(ids)) {
+            return Collections.emptyList();
+        }
+        ReceivedsResult result;
+        try {
+            result = this.pushClient.getReceivedsDetail(ids);
+        } catch (Exception e) {
+            log.warn("JPush delivery get failed: {}", e.getMessage());
+            return Collections.emptyList();
+        }
+        return ObjectUtils.ifNull(result.received_list, Collections::emptyList);
+    }
+
+    @Override
+    public String code2mobile(@NonNull String token) {
+        // 根据令牌获取手机号
+        Map<String, String> body = ImmutableMap.of("loginToken", token);
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Authorization", this.authorization);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        HttpEntity<?> entity = new HttpEntity<>(body, headers);
+        Map<?, ?> response = RestContextHolder.exchange(CODE2MOBILE_URL, HttpMethod.POST, entity, Map.class);
+        Integer code = response == null ? null : (Integer) response.get("code");
+        if (code == null) {
+            throw new RuntimeException("Invalid jpush response");
+        } else if (code != 8000) {
+            throw new RuntimeException(code + ", " + response.get("content"));
+        }
+
+        // 解码手机号
+        String mobile = (String) response.get("phone");
+        byte[] bytes = Base64.getDecoder().decode(mobile);
+        PrivateKey key = Objects.requireNonNull(this.key, "JPush key not specified");
+        try {
+            Cipher cipher = Cipher.getInstance("RSA");
+            cipher.init(Cipher.DECRYPT_MODE, key);
+            return new String(cipher.doFinal(bytes));
+        } catch (GeneralSecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     @Override
     public boolean register(@NonNull RegisterInfo... registrations) {
         if (registrations.length == 0) {
@@ -221,26 +294,6 @@ public class DefaultJPushHandler implements JPushHandler {
         }
     }
 
-    /**
-     * 获取消息投递结果
-     *
-     * @param ids 消息ID(多个ID之间使用","号隔开,最多最多支持 100 个消息ID)
-     * @return 投递结果列表
-     */
-    private List<ReceivedsResult.Received> getDeliveries(String ids) {
-        if (StringUtils.isEmpty(ids)) {
-            return Collections.emptyList();
-        }
-        ReceivedsResult result;
-        try {
-            result = this.pushClient.getReceivedsDetail(ids);
-        } catch (Exception e) {
-            log.warn("JPush delivery get failed: {}", e.getMessage());
-            return Collections.emptyList();
-        }
-        return ObjectUtils.ifNull(result.received_list, Collections::emptyList);
-    }
-
     @Override
     public ReceivedsResult.Received getDelivery(@NonNull Long id) {
         List<ReceivedsResult.Received> deliveries = this.getDeliveries(String.valueOf(id));

+ 8 - 0
framework-jpush/src/main/java/com/chelvc/framework/jpush/JPushHandler.java

@@ -37,6 +37,14 @@ public interface JPushHandler {
      */
     String getAuthorization();
 
+    /**
+     * 根据临时令牌获取手机号
+     *
+     * @param token 临时令牌
+     * @return 手机号
+     */
+    String code2mobile(String token);
+
     /**
      * 账号注册
      *

+ 5 - 0
framework-jpush/src/main/java/com/chelvc/framework/jpush/config/JPushProperties.java

@@ -14,6 +14,11 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 @ConfigurationProperties("jpush")
 public class JPushProperties {
+    /**
+     * 解密私钥
+     */
+    private String key;
+
     /**
      * 应用标识
      */