yumeng 9 saat önce
ebeveyn
işleme
d963740945

+ 7 - 8
src/main/java/com/nuojing/media/auth/client/KuaishouMediaClient.java

@@ -20,7 +20,7 @@ import java.util.Map;
 public class KuaishouMediaClient {
 
     private static final String TOKEN_URL = "https://ad.e.kuaishou.com/rest/openapi/oauth2/authorize/access_token";
-    private static final String APPROVAL_LIST_URL = "https://ad.e.kuaishou.com/rest/openapi/oauth2/authorize/approval/list";
+    private static final String ADVERTISER_LIST_URL = "https://ad.e.kuaishou.com/rest/openapi/gw/uc/v1/advertisers";
 
     private final ObjectMapper objectMapper;
     private final RestTemplate restTemplate = new RestTemplate();
@@ -33,14 +33,13 @@ public class KuaishouMediaClient {
         return postJson(TOKEN_URL, body);
     }
 
-    public JsonNode approvalList(MediaAuthConfig config, String accessToken, int pageNo) {
+    public JsonNode advertiserList(String accessToken, long advertiserId) {
         Map<String, Object> body = new HashMap<>();
-        body.put("app_id", config.getAppId());
-        body.put("secret", config.getAppSecret());
-        body.put("access_token", accessToken);
-        body.put("page_no", pageNo);
-        body.put("page_size", 1000);
-        return postJson(APPROVAL_LIST_URL, body);
+        body.put("advertiser_id", advertiserId);
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        headers.set("Access-Token", accessToken);
+        return parse(restTemplate.postForObject(ADVERTISER_LIST_URL, new HttpEntity<>(body, headers), String.class));
     }
 
     public JsonNode requireSuccess(JsonNode response, String action) {

+ 9 - 8
src/main/java/com/nuojing/media/auth/client/TencentMediaClient.java

@@ -17,7 +17,7 @@ import java.util.UUID;
 public class TencentMediaClient {
 
     private static final String TOKEN_URL = "https://api.e.qq.com/oauth/token";
-    private static final String BM_RELATIONS_URL = "https://api.e.qq.com/v1.1/business_manager_relations/get";
+    private static final String ORG_RELATION_URL = "https://api.e.qq.com/v3.0/organization_account_relation/get";
     private static final int PAGE_SIZE = 100;
 
     private final ObjectMapper objectMapper;
@@ -36,16 +36,17 @@ public class TencentMediaClient {
         return parse(restTemplate.getForObject(url, String.class));
     }
 
-    public JsonNode businessManagerRelations(String accessToken, int page) {
-        String url = UriComponentsBuilder.fromUriString(BM_RELATIONS_URL)
+    public JsonNode organizationAccountRelations(String accessToken, Integer cursor) {
+        UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(ORG_RELATION_URL)
                 .queryParam("access_token", accessToken)
                 .queryParam("timestamp", System.currentTimeMillis() / 1000)
                 .queryParam("nonce", UUID.randomUUID().toString().replace("-", ""))
-                .queryParam("page", page)
-                .queryParam("page_size", PAGE_SIZE)
-                .build()
-                .encode()
-                .toUriString();
+                .queryParam("pagination_mode", "PAGINATION_MODE_CURSOR")
+                .queryParam("page_size", PAGE_SIZE);
+        if (cursor != null) {
+            builder.queryParam("cursor", cursor);
+        }
+        String url = builder.build().encode().toUriString();
         return parse(restTemplate.getForObject(url, String.class));
     }
 

+ 27 - 49
src/main/java/com/nuojing/media/auth/service/impl/MediaAuthServiceImpl.java

@@ -288,51 +288,38 @@ public class MediaAuthServiceImpl implements MediaAuthService {
             throw new BusinessException(500, "获取快手token失败:access_token为空");
         }
 
-        // 广告账户来源:token响应的advertiser_ids(广告账户授权场景);为空则用approval/list拉取(用户授权/服务商场景)
-        List<Long> advertiserIds = new ArrayList<>();
-        JsonNode tokenAdvertiserIds = tokenData.path("advertiser_ids");
-        if (tokenAdvertiserIds.isArray() && !tokenAdvertiserIds.isEmpty()) {
-            tokenAdvertiserIds.forEach(node -> advertiserIds.add(node.asLong()));
-        } else {
-            advertiserIds.addAll(syncKuaishouApprovalList(config, accessToken));
-        }
-        if (advertiserIds.isEmpty()) {
-            throw new BusinessException(500, "未获取到快手授权广告账户");
+        // 管家标识取快手ID(用户授权场景token响应必返user_id)
+        Long adminAdvertiserId = tokenData.path("user_id").asLong(0);
+        if (adminAdvertiserId <= 0) {
+            throw new BusinessException(500, "未获取到快手授权用户ID:user_id为空");
         }
 
         Long userId = parseStateUserId(params.get("state"));
-        // 磁力引擎token响应未单独返回管家账户ID,优先取响应内的账户字段,否则以首个广告账户作为管家标识
-        Long adminAdvertiserId = resolveKuaishouAdminId(tokenData, advertiserIds);
         MediaAuthAccount authAccount = baseAuthAccount(config, MediaType.KUAISHOU, userId, adminAdvertiserId, accessToken, refreshToken);
         authAccount.setRawResponse(toJson(tokenData));
         mediaAuthMapper.replaceAuthAccount(authAccount);
 
-        for (Long advertiserId : advertiserIds) {
-            mediaAuthMapper.replaceAdvertiserAccount(toKuaishouAdvertiserAccount(adminAdvertiserId, advertiserId));
-        }
+        syncKuaishouAdvertisers(accessToken, adminAdvertiserId);
         return adminAdvertiserId;
     }
 
-    private List<Long> syncKuaishouApprovalList(MediaAuthConfig config, String accessToken) {
-        List<Long> advertiserIds = new ArrayList<>();
-        int pageNo = 1;
-        boolean isEnd;
-        do {
+    private void syncKuaishouAdvertisers(String accessToken, Long adminAdvertiserId) {
+        try {
             JsonNode data = kuaishouMediaClient.requireSuccess(
-                    kuaishouMediaClient.approvalList(config, accessToken, pageNo), "获取快手授权广告账户列表");
+                    kuaishouMediaClient.advertiserList(accessToken, adminAdvertiserId), "获取快手广告账户列表");
             JsonNode details = data.path("details");
             if (details.isArray()) {
-                for (JsonNode detail : details) {
-                    long advertiserId = detail.asLong(0);
+                for (JsonNode item : details) {
+                    long advertiserId = item.path("advertiser_id").asLong(0);
                     if (advertiserId > 0) {
-                        advertiserIds.add(advertiserId);
+                        mediaAuthMapper.replaceAdvertiserAccount(toKuaishouAdvertiserAccount(adminAdvertiserId, advertiserId,
+                                item.path("advertiser_name").asText(null)));
                     }
                 }
             }
-            isEnd = data.path("isEnd").asBoolean(true);
-            pageNo++;
-        } while (!isEnd);
-        return advertiserIds;
+        } catch (Exception ex) {
+            log.warn("获取快手广告账户列表失败,仅保留授权信息:adminAdvertiserId={}", adminAdvertiserId, ex);
+        }
     }
 
     private Long handleTencentCallback(Map<String, String> params) {
@@ -363,18 +350,17 @@ public class MediaAuthServiceImpl implements MediaAuthService {
     }
 
     private void syncTencentAdvertisers(String accessToken, Long adminAdvertiserId) {
-        int page = 1;
-        int totalPage = 1;
+        Integer cursor = null;
         do {
-            JsonNode relations;
+            JsonNode data;
             try {
-                relations = tencentMediaClient.requireSuccess(
-                        tencentMediaClient.businessManagerRelations(accessToken, page), "获取腾讯商务管家广告主");
+                data = tencentMediaClient.requireSuccess(
+                        tencentMediaClient.organizationAccountRelations(accessToken, cursor), "获取腾讯广告账户列表");
             } catch (Exception ex) {
-                log.warn("获取腾讯商务管家广告主列表失败,仅保留管家授权信息:adminAdvertiserId={}", adminAdvertiserId, ex);
+                log.warn("获取腾讯广告账户列表失败,仅保留授权信息:adminAdvertiserId={}", adminAdvertiserId, ex);
                 return;
             }
-            JsonNode list = relations.path("list");
+            JsonNode list = data.path("list");
             if (list.isArray()) {
                 for (JsonNode item : list) {
                     long advertiserId = item.path("account_id").asLong(0);
@@ -383,9 +369,10 @@ public class MediaAuthServiceImpl implements MediaAuthService {
                     }
                 }
             }
-            totalPage = Math.max(relations.path("page_info").path("total_page").asInt(page), page);
-            page++;
-        } while (page <= totalPage);
+            JsonNode pageInfo = data.path("cursor_page_info");
+            cursor = pageInfo.path("has_more").asBoolean(false) && pageInfo.path("cursor").isNumber()
+                    ? pageInfo.path("cursor").asInt() : null;
+        } while (cursor != null);
     }
 
     private MediaAuthConfig requireConfig(MediaType media) {
@@ -396,16 +383,6 @@ public class MediaAuthServiceImpl implements MediaAuthService {
         return config;
     }
 
-    private Long resolveKuaishouAdminId(JsonNode tokenData, List<Long> advertiserIds) {
-        for (String field : new String[]{"user_id", "account_id", "corporation_id"}) {
-            long value = tokenData.path(field).asLong(0);
-            if (value > 0) {
-                return value;
-            }
-        }
-        return advertiserIds.get(0);
-    }
-
     private MediaAuthAccount baseAuthAccount(MediaAuthConfig config, MediaType media, Long userId, Long adminAdvertiserId, String accessToken, String refreshToken) {
         MediaAuthAccount account = new MediaAuthAccount();
         account.setMediaType(media.getMediaId());
@@ -418,11 +395,12 @@ public class MediaAuthServiceImpl implements MediaAuthService {
         return account;
     }
 
-    private MediaAdvertiserAccount toKuaishouAdvertiserAccount(Long adminAdvertiserId, Long advertiserId) {
+    private MediaAdvertiserAccount toKuaishouAdvertiserAccount(Long adminAdvertiserId, Long advertiserId, String advertiserName) {
         MediaAdvertiserAccount account = new MediaAdvertiserAccount();
         account.setMediaType(MediaType.KUAISHOU.getMediaId());
         account.setAdminAdvertiserId(adminAdvertiserId);
         account.setAdvertiserId(advertiserId);
+        account.setAdvertiserName(advertiserName);
         account.setIsValid(1);
         account.setRawResponse("{\"advertiser_id\":" + advertiserId + "}");
         return account;