WPS开发平台,请求`获取盘列表`接口报错 400000003 kso: PermissionDenied access_token verify err: invalid_scope

阅读次数 13

基本类似的代码,请求获取公司信息和应用信息都是正常的,但是请求drive相关的接口都会报错 { code: 400000003, message: kso: PermissionDenied access_token verify err: invalid_scope {"desc":"The requested scope is invalid, unknown, or malformed. The request scopes 'kso.drive.readwrite' has not been granted or is not allowed to be requested."}, cause: , desc: The requested scope is invalid, unknown, or malformed. The request scopes 'kso.drive.readwrite' has not been granted or is not allowed to be requested., tip:
}

测试代码如下:

const axios = require("axios");
const crypto = require("crypto");

const BASE_URL = "https://openapi.wps.cn";
const APP_ID = ""; // 请替换为实际的 APPID
const APP_SECRET_KEY = ""; // 请替换为实际的 APPKEY

/**
 * 生成 RFC1123 格式的时间字符串
 * @returns {string} RFC1123 格式的日期字符串
 */
function getRFC1123Date() {
  return new Date().toUTCString();
}

/**
 * 获取 Access Token
 * @returns {Promise} 返回 access_token
 */
async function getAccessToken() {
  const url = `${BASE_URL}/oauth2/token`;
  const headers = { "Content-Type": "application/x-www-form-urlencoded" };
  const body = new URLSearchParams({
    grant_type: "client_credentials",
    client_id: APP_ID,
    client_secret: APP_SECRET_KEY,
  }).toString();

  try {
    const response = await axios.post(url, body, { headers });
    return response.data.access_token;
  } catch (error) {
    console.error(
      "Error fetching access token:",
      error.response ? error.response.data : error.message
    );
    throw error;
  }
}

/**
 * 生成 KSO-1 签名
 * @param {string} method 请求方法 (GET, POST, etc.)
 * @param {string} requestUri 请求 URI (包含 query 参数)
 * @param {string} contentType 请求的 Content-Type
 * @param {string} ksoDate 请求的 X-Kso-Date (RFC1123 格式时间)
 * @param {string} requestBody 请求体字符串 (如果没有,传空字符串 "")
 * @returns {string} 计算后的签名字符串
 */
function generateSignature(
  method,
  requestUri,
  contentType,
  ksoDate,
  requestBody
) {
  const requestBodyHash = requestBody
    ? crypto.createHash("sha256").update(requestBody, "utf8").digest("hex")
    : "";
  const stringToSign = `KSO-1${method}${requestUri}${contentType}${ksoDate}${requestBodyHash}`;

  return crypto
    .createHmac("sha256", APP_SECRET_KEY)
    .update(stringToSign, "utf8")
    .digest("hex");
}

/**
 * 获取本企业信息
 * @param {string} accessToken 授权 token
 * @returns {Promise} 企业信息数据
 */
async function getCompanyInfo(accessToken) {
  const method = "GET";
  const requestUri = "/v7/companies/current";
  const contentType = "application/json";
  const ksoDate = getRFC1123Date();
  const requestBody = "";

  const signature = generateSignature(
    method,
    requestUri,
    contentType,
    ksoDate,
    requestBody
  );
  const authorizationHeader = `KSO-1 ${APP_ID}:${signature}`;

  const headers = {
    "Content-Type": contentType,
    "X-Kso-Date": ksoDate,
    "X-Kso-Authorization": authorizationHeader,
    Authorization: `Bearer ${accessToken}`,
  };

  try {
    const response = await axios.get(BASE_URL + requestUri, { headers });
    return response.data;
  } catch (error) {
    console.error(
      "Error fetching company info:",
      error.response ? error.response.data : error.message
    );
    throw error;
  }
}

/**
 * 创建新的驱动盘
 * @param {string} accessToken 授权 token
 * @param {Object} driveData 驱动盘信息
 * @returns {Promise} 新建驱动盘数据
 */
async function createDrive(accessToken, driveData) {
  const method = "POST";
  const requestUri = "/v7/drives/create";
  const contentType = "application/json";
  const ksoDate = getRFC1123Date();
  const requestBody = JSON.stringify(driveData);

  const signature = generateSignature(
    method,
    requestUri,
    contentType,
    ksoDate,
    requestBody
  );
  const authorizationHeader = `KSO-1 ${APP_ID}:${signature}`;

  const headers = {
    "Content-Type": contentType,
    "X-Kso-Date": ksoDate,
    "X-Kso-Authorization": authorizationHeader,
    Authorization: `Bearer ${accessToken}`,
  };

  try {
    const response = await axios.post(BASE_URL + requestUri, requestBody, {
      headers,
    });
    return response.data;
  } catch (error) {
    console.error(
      "Error creating drive:",
      error.response ? error.response.data : error.message
    );
    throw error;
  }
}

/**
 * 获取 WPS 盘列表
 * @param {string} accessToken 授权 token
 * @param {Object} params 请求参数
 * @returns {Promise} 盘列表数据
 */
async function getDrives(accessToken, params) {
  const method = "GET";
  const requestUri = "/v7/drives";
  const fullRequestUri =
    requestUri + (params ? `?${new URLSearchParams(params).toString()}` : "");
  const contentType = "application/json";
  const ksoDate = getRFC1123Date();
  const requestBody = "";

  const signature = generateSignature(
    method,
    fullRequestUri,
    contentType,
    ksoDate,
    requestBody
  );
  const authorizationHeader = `KSO-1 ${APP_ID}:${signature}`;

  const headers = {
    "Content-Type": contentType,
    "X-Kso-Date": ksoDate,
    "X-Kso-Authorization": authorizationHeader,
    Authorization: `Bearer ${accessToken}`,
  };

  try {
    const response = await axios.get(BASE_URL + fullRequestUri, { headers });
    return response.data;
  } catch (error) {
    console.error(
      "Error fetching drives:",
      error.response ? error.response.data : error.message
    );
    throw error;
  }
}

/**
 * 获取应用信息
 * @param {string} accessToken 授权 token
 * @returns {Promise} 应用信息数据
 */
async function getApplicationInfo(accessToken) {
  const method = "GET";
  const requestUri = "/v7/developer/applications/current";
  const contentType = "application/json";
  const ksoDate = getRFC1123Date();
  const requestBody = ""; // GET 请求没有请求体

  // 生成 KSO-1 签名
  const signature = generateSignature(
    method,
    requestUri,
    contentType,
    ksoDate,
    requestBody
  );
  const authorizationHeader = `KSO-1 ${APP_ID}:${signature}`;

  // 设置请求头
  const headers = {
    "Content-Type": contentType,
    "X-Kso-Date": ksoDate,
    "X-Kso-Authorization": authorizationHeader,
    Authorization: `Bearer ${accessToken}`, // 认证头
  };

  try {
    // 发送 GET 请求
    const response = await axios.get(BASE_URL + requestUri, { headers });
    return response.data;
  } catch (error) {
    console.error(
      "Error fetching application info:",
      error.response ? error.response.data : error.message
    );
    throw error;
  }
}

// 主函数
async function main() {
  let accessToken;
  try {
    accessToken = await getAccessToken();
    console.log("Access Token:", accessToken);
  } catch (error) {
    console.error("Failed to retrieve access token.");
    return;
  }

  try {
    const companyInfo = await getCompanyInfo(accessToken);
    console.log("Company Info:", JSON.stringify(companyInfo, null, 2));
  } catch (error) {
    console.error("Failed to retrieve company info.");
  }

  try {
    const queryParams = {
      // allotee_id: "",
      allotee_type: "app", // user, group, app
      page_size: 100,
      with_ext_attrs: true,
    };

    const driveList = await getDrives(accessToken, queryParams);
    console.log("Drive List:", JSON.stringify(driveList, null, 2));
  } catch (error) {
    console.error("Failed to retrieve drive list.");
  }

  // try {
  //   const newDriveData = {
  //     allotee_id: APP_ID,
  //     allotee_type: "app", // user, group, app
  //     name: "NewDriveName",
  //     description: "This is a test drive",
  //     // total_quota: 104857600, // 100MB
  //     // ext_attrs: [
  //     //   {
  //     //     name: "custom_attr",
  //     //     value: "custom_value",
  //     //   },
  //     // ],
  //   };

  //   const newDrive = await createDrive(accessToken, newDriveData);
  //   console.log("New Drive Created:", JSON.stringify(newDrive, null, 2));
  // } catch (error) {
  //   console.error("Failed to create new drive.");
  // }

  try {
    const appInfo = await getApplicationInfo(accessToken);
    console.log("Application Info:", JSON.stringify(appInfo, null, 2));
  } catch (error) {
    console.error("Failed to retrieve application info.");
  }
}
main();


输出结果 image.png

1 Answers

代码贴不上去。。。 输出结果如下:image.png