ソースを参照

亚马逊授权测试案例

肖佳斌 10 ヶ月 前
コミット
2729c5bf0f

+ 23 - 0
raycos_common/src/main/java/com/raycos/raycoscommon/Internal/datacenterapi/TbAmzAuthorize.java

@@ -0,0 +1,23 @@
+package com.raycos.raycoscommon.Internal.datacenterapi;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 14:28
+ */
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class TbAmzAuthorize {
+
+    private  Long id;
+    private  String sellingPartnerId;
+    private  String mwsAuthToken;
+    private  String spapiOauthCode;
+
+
+}

+ 212 - 0
raycos_datacenter_api/src/main/java/com/raycos/raycosdatacenterapi/authorize/Amazon.java

@@ -0,0 +1,212 @@
+package com.raycos.raycosdatacenterapi.authorize;
+
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 10:55
+ *
+ *  亚马逊授权
+ */
+@Slf4j
+public class Amazon {
+
+
+
+
+    // 用户通过页面调用Amazon授权 接口
+    // 授权成功后 亚马逊回调  我的接口 入参:
+    /**
+     * state	步骤 2 中的 state 值。
+     * selling_partner_id	授权您的应用程序的销售合作伙伴的标识符。
+     * mws_auth_token	(仅限卖家应用程序)您在为 Amazon Marketplace Web Service 调用创建查询字符串时指定的值。
+     * spapi_oauth_code	用于生成 LWA 刷新令牌的 Login with Amazon (LWA) 授权码(请参阅第 5 步)。
+     */
+    //  我拿到 spapi_oauth_code 去调用刷新令牌接口
+    //  发送:
+    /**
+     * grant_type	请求的访问授权的类型。必须是 。authorization_code
+     * code	您在步骤 4 中收到的 LWA 授权码。Amazon 会向您发送授权信息。
+     * redirect_uri	应用程序的重定向 URI。
+     * client_id	LWA 凭证的一部分。要获取此值,请参阅 查看您的开发者信息。
+     * client_secret	LWA 凭证的一部分。要获取此值,请参阅 查看您的开发者信息。
+     */
+    //  接收:
+    /**
+     * access_token	一个令牌,用于授权您的应用程序代表销售合作伙伴执行某些操作。有关详细信息,请参阅连接到 SP-API。
+     * token_type	返回的 token 类型。应该是 bearer。
+     * expires_in	访问令牌失效前的秒数。
+     * refresh_token	可用于生成新访问令牌的长寿命令牌。有关详细信息,请参阅连接到 SP-API。
+     */
+
+
+
+
+// LWA客户端编码
+    private  static  String  client_id = "amzn1.application-oa2-client.2d001c4aeaaf438f98ee0b07070c1cf8";
+    // LWA客户端秘钥
+    private  static  String  client_secret = "amzn1.oa2-cs.v1.52b13f4ce04e83046b3426b620b6bfb94fd3ce61c815c6f68858af69d0ccbe54";
+
+
+
+    public static String getAccessToken(String code) {
+        try {
+
+            String url = "https://api.amazon.com/auth/o2/token";
+            Map<String, String> map = new HashMap<>();
+            map.put("grant_type", "authorization_code");
+            map.put("code", code);
+            map.put("client_id", client_id);
+            map.put("redirect_uri", "https://api.mabangerp.com/fba/api/v1/authCode");
+            map.put("client_secret", client_secret);
+            Map<String, String> headerMap = new HashMap<>();
+//            log.info();
+            headerMap.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
+//            String response = HttpClientUtil.httpPostForm(url, map, headerMap, null, 5000);
+
+//            logger.info(", get accessToken response : " + response);
+            return null;
+        } catch (Exception e) {
+            e.printStackTrace();
+//            logger.error(e.getMessage(), e);
+        }
+        return "报错";
+    }
+//
+//    public static String refreshAccessToken(String refresh_token) {
+//        try {
+//            String url = "https://api.amazon.com/auth/o2/token";
+//            Map<String, String> map = new HashMap<>();
+//            map.put("grant_type", "refresh_token");
+//            map.put("refresh_token", refresh_token);
+//            map.put("client_id", client_id);
+//            map.put("client_secret", client_secret);
+//            Map<String, String> headerMap = new HashMap<>();
+//            logger.info(JSONObject.toJSONString(map));
+//            headerMap.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
+//            String response = HttpClientUtil.httpPostForm(url, map, headerMap, null, 5000);
+//            logger.info("refresh access_token response : " + response);
+//            return response;
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//            logger.error(e.getMessage(), e);
+//        }
+//        return "报错";
+//    }
+//
+//
+//    public static String httpPostForm(String requestUrl, Map<String, String> paramMap,
+//                                      Map<String, String> headerMap, String encode, int timeOut) {
+//        String response = "";
+//        if (encode == null) {
+//            encode = "utf-8";
+//        }
+//
+//        // HttpClients.createDefault() 等价于 HttpClientBuilder.create().build();
+//        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
+//        HttpPost httpPost = new HttpPost(requestUrl);
+//
+//        // 设置超时时间
+//        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut)
+//                .setConnectTimeout(timeOut).setSocketTimeout(timeOut).build();
+//        httpPost.setConfig(requestConfig);
+//
+//        // 设置header
+//        if (headerMap != null && headerMap.size() > 0) {
+//            for (String key : headerMap.keySet()) {
+//                httpPost.setHeader(key, headerMap.get(key));
+//            }
+//        }
+//
+//        // 设置Param
+//        if (paramMap != null && paramMap.size() > 0) {
+//
+//            List<NameValuePair> paramList = new ArrayList<NameValuePair>();
+//            for (String key : paramMap.keySet()) {
+//                paramList.add(new BasicNameValuePair(key, paramMap.get(key)));
+//            }
+//
+//            try {
+//                httpPost.setEntity(new UrlEncodedFormEntity(paramList, encode));
+//            } catch (UnsupportedEncodingException e) {
+//                e.printStackTrace();
+//            }
+//
+//        }
+//
+//        CloseableHttpResponse httpResponse = null;
+//        try {
+//            httpResponse = closeableHttpClient.execute(httpPost);
+//            HttpEntity entity = httpResponse.getEntity();
+//            byte[] bytes = (entity == null ? null : EntityUtils.toByteArray(entity));
+//            String content = (bytes == null ? null : new String(bytes, encode));
+//            response = content;
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        } finally {
+//            try {
+//                if (httpResponse != null) {
+//                    httpResponse.close();
+//                }
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//            }
+//        }
+//
+//        try {
+//            // 关闭连接、释放资源
+//            if (closeableHttpClient != null) {
+//                closeableHttpClient.close();
+//            }
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+//
+//        return response;
+//    }
+//
+//    /**
+//
+//     https://sellingpartnerapi-na.amazon.com/apps/authorize/consent
+//     https://sellingpartnerapi-eu.amazon.com/apps/authorize/consent
+//     https://sellingpartnerapi-fe.amazon.com/apps/authorize/consent
+//
+//     https://www.amazon.com/ap/oa?client_id=AKIAJQM2XW6X65DC5OWA
+//     &scope=profile
+//     &response_type=code
+//     &state=208257577ll0975l93l2l59l895857093449424
+//     &redirect_uri=https://client.example.com/auth_popup/token
+//     &code_challenge=Fw7s3XHRVb2m1nT7s646UrYiYLMJ54as0ZIU_injyqw
+//     &code_challenge_method=S256
+//
+//     if ($this->site == 'eu') {
+//     return 'https://sellercentral-europe.amazon.com/apps/authorize/consent';
+//     } elseif ($this->site == 'fe') {
+//     if ($this->countryCode == 'au') {
+//     return 'https://sellercentral.amazon.com.au/apps/authorize/consent';
+//     } elseif ($this->countryCode == 'jp') {
+//     return 'https://sellercentral-japan.amazon.com/apps/authorize/consent';
+//     } else {
+//     //新加坡
+//     return 'https://sellercentral.amazon.sg/apps/authorize/consent';
+//     }
+//     } else {
+//     return 'https://sellercentral.amazon.com/apps/authorize/consent';
+//     }
+//
+//     //     https://raycos.com.cn/authorize
+//
+//
+//
+//     */
+
+
+
+
+
+
+}

+ 77 - 0
raycos_datacenter_api/src/main/java/com/raycos/raycosdatacenterapi/authorize/AmazonController.java

@@ -0,0 +1,77 @@
+package com.raycos.raycosdatacenterapi.authorize;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.raycos.raycoscommon.Internal.Result;
+import com.raycos.raycoscommon.Internal.datacenterapi.TbAmzAuthorize;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 13:25
+ */
+
+@RestController
+@Slf4j
+@RequestMapping("/erp/amz")
+public class AmazonController {
+
+
+    @Autowired
+    private AmzAuthorizeService authorizeService;
+
+    @GetMapping("/authcode")
+    public Result<String> getSpapiOauthCode(
+            @RequestParam(value = "state") String state,
+            @RequestParam(value = "selling_partner_id") String sellingPartnerId,
+            @RequestParam("mws_auth_token") String mwsAuthToken,
+            @RequestParam("spapi_oauth_code") String spapiOauthCode
+    ) {
+        Result<String> rt = new Result<>();
+        log.info("来了老弟 !! ");
+
+        try {
+            TbAmzAuthorize taa = new TbAmzAuthorize();
+            taa.setSpapiOauthCode(spapiOauthCode);
+            taa.setMwsAuthToken(mwsAuthToken);
+            taa.setSellingPartnerId(sellingPartnerId);
+
+            log.info("亚马逊授权成功 重定向接口 接收参数 = " + JSONObject.toJSONString(taa));
+
+            authorizeService.addAmzAuthorize(taa);
+
+            rt.success();
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error(" 查询异常  ", e);
+            rt.fail();
+        }
+        return rt;
+    }
+
+
+
+
+    @GetMapping("/sel")
+    public Result<List<TbAmzAuthorize>> selectAll() {
+
+        List<TbAmzAuthorize> list = null;
+        try {
+
+            list = authorizeService.selectAll();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error(" 查询异常  ", e);
+        }
+        return new Result<List<TbAmzAuthorize>>().success(list);
+    }
+
+
+}

+ 19 - 0
raycos_datacenter_api/src/main/java/com/raycos/raycosdatacenterapi/authorize/AmzAuthorizeService.java

@@ -0,0 +1,19 @@
+package com.raycos.raycosdatacenterapi.authorize;
+
+import com.raycos.raycoscommon.Internal.datacenterapi.TbAmzAuthorize;
+
+import java.util.List;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 14:40
+ */
+
+public interface AmzAuthorizeService {
+
+    List<TbAmzAuthorize> selectAll()throws   Exception;
+
+    void  addAmzAuthorize ( TbAmzAuthorize tbAmzAuthorize) throws Exception;
+
+    void getAccessToken(TbAmzAuthorize tbAmzAuthorize ) throws Exception;
+}

+ 60 - 0
raycos_datacenter_api/src/main/java/com/raycos/raycosdatacenterapi/authorize/impl/AmzAuthorizeServiceImpl.java

@@ -0,0 +1,60 @@
+package com.raycos.raycosdatacenterapi.authorize.impl;
+
+import com.raycos.raycoscommon.Internal.datacenterapi.TbAmzAuthorize;
+import com.raycos.raycosdatacenterapi.authorize.AmzAuthorizeService;
+import com.raycos.raycosdatacenterapi.mapper.TbAmzAuthorizeMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.List;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 14:41
+ */
+
+@Service
+public class AmzAuthorizeServiceImpl implements AmzAuthorizeService {
+
+
+    @Autowired
+    private TbAmzAuthorizeMapper tbAmzAuthorizeMapper;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Override
+    public List<TbAmzAuthorize> selectAll() throws Exception {
+
+
+        List<TbAmzAuthorize> list = tbAmzAuthorizeMapper.selectList(null);
+
+        return list;
+
+
+    }
+
+    @Override
+    public void addAmzAuthorize(TbAmzAuthorize tbAmzAuthorize) throws Exception {
+        tbAmzAuthorizeMapper.insert(tbAmzAuthorize);
+    }
+
+    /**
+     * 调亚马逊接口 获取 AccessToken( 长令牌、短令牌)
+     *
+     * @param tbAmzAuthorize
+     * @throws Exception
+     */
+    @Override
+    public void getAccessToken(TbAmzAuthorize tbAmzAuthorize) throws Exception {
+
+        //
+
+//        restTemplate.
+
+
+    }
+
+
+}

+ 22 - 0
raycos_datacenter_api/src/main/java/com/raycos/raycosdatacenterapi/config/RestTemplateConfig.java

@@ -0,0 +1,22 @@
+package com.raycos.raycosdatacenterapi.config;
+
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 16:34
+ */
+
+@Configuration
+public class RestTemplateConfig {
+
+    @Bean
+    @LoadBalanced
+    public RestTemplate restTemplate() {
+        System.out.println("来了吗老弟 ");
+        return new RestTemplate();
+    }
+}

+ 14 - 0
raycos_datacenter_api/src/main/java/com/raycos/raycosdatacenterapi/mapper/TbAmzAuthorizeMapper.java

@@ -0,0 +1,14 @@
+package com.raycos.raycosdatacenterapi.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.raycos.raycoscommon.Internal.datacenterapi.TbAmzAuthorize;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 14:26
+ */
+
+public interface TbAmzAuthorizeMapper extends BaseMapper<TbAmzAuthorize> {
+
+
+}

+ 30 - 0
raycos_datacenter_api/src/main/java/com/raycos/raycosdatacenterapi/scheduledtasks/RefreshAmazonToken.java

@@ -0,0 +1,30 @@
+package com.raycos.raycosdatacenterapi.scheduledtasks;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * @Author: xiaojiabin
+ * @Date: 2024/9/2 16:12
+ */
+
+@Component
+@Slf4j
+public class RefreshAmazonToken {
+
+
+    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+    @Scheduled(fixedRate = 5000)
+    public void reportCurrentTime() {
+
+        log.info("现在时间是:" + dateTimeFormatter.format(LocalDateTime.now()));
+    }
+
+
+
+}

+ 104 - 0
raycos_datacenter_api/src/main/resources/logback-spring.xml

@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- logback默认每60秒扫描该文件一次,如果有变动则用变动后的配置文件。 -->
+<configuration scan="false">
+
+    <!-- ==============================================开发环境=========================================== -->
+    <springProfile name="dev">
+
+        <!-- 控制台输出 -->
+        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            </encoder>
+        </appender>
+
+        <!-- 日志输出级别 -->
+        <root level="INFO">
+            <appender-ref ref="STDOUT"/>
+        </root>
+    </springProfile>
+
+    <!-- ==============================================生产环境=========================================== -->
+    <springProfile name="prod">
+        <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
+        <property name="LOG_HOME" value="./log"/>
+
+        <!-- 控制台输出 -->
+        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            </encoder>
+        </appender>
+
+        <!-- 按照每天生成日志文件 -->
+        <appender name="INFO_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+
+            <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
+            如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
+            的日志改名为今天的日期。即,<File> 的日志都是当天的。
+            -->
+            <file>${LOG_HOME}/info.log</file>
+
+            <!--滚动策略,按照大小时间滚动 SizeAndTimeBasedRollingPolicy-->
+            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                <!--日志文件输出的文件名-->
+                <FileNamePattern>${LOG_HOME}/info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+                <!--只保留最近30天的日志-->
+                <MaxHistory>30</MaxHistory>
+                <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
+                <totalSizeCap>1GB</totalSizeCap>
+                <MaxFileSize>10MB</MaxFileSize>
+            </rollingPolicy>
+
+            <!--日志输出编码格式化-->
+            <encoder>
+                <charset>UTF-8</charset>
+                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+                </pattern>
+            </encoder>
+
+            <!--过滤器,只有过滤到指定级别的日志信息才会输出,如果level为ERROR,那么控制台只会输出ERROR日志-->
+            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+                <level>INFO</level>
+            </filter>
+        </appender>
+
+        <!-- 按照每天生成日志文件 -->
+        <appender name="ERROR_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+            <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
+             如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
+             的日志改名为今天的日期。即,<File> 的日志都是当天的。
+            -->
+            <file>${LOG_HOME}/error.log</file>
+            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                <!--日志文件输出的文件名-->
+                <FileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+                <MaxHistory>30</MaxHistory>
+                <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
+                <totalSizeCap>1GB</totalSizeCap>
+                <MaxFileSize>10MB</MaxFileSize>
+            </rollingPolicy>
+            <encoder>
+                <charset>UTF-8</charset>
+                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+                </pattern>
+            </encoder>
+            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+                <level>ERROR</level>
+            </filter>
+        </appender>
+
+        <!--指定最基础的日志输出级别-->
+        <root level="INFO">
+            <!--appender将会添加到这个loger-->
+            <appender-ref ref="STDOUT"/>
+            <appender-ref ref="INFO_APPENDER"/>
+            <appender-ref ref="ERROR_APPENDER"/>
+        </root>
+    </springProfile>
+</configuration>