Skip to content

Node.js SDK

提供 A7Client 参考实现,仅依赖 Node.js 内置模块(crypto / fetch)。要求 Node.js 18+(fetch 已内置)。

完整参考实现

a7client.js

javascript
const crypto = require('crypto');

const BASE = 'https://api.a7p.cn/api/verify';

class A7Client {
  constructor(appId, appKey, base = BASE) {
    this.appId = String(appId);
    this.appKey = appKey;
    this.base = base;
    this.apiPassword = '';
  }

  static md5(text) {
    return crypto.createHash('md5').update(text, 'utf8').digest('hex');
  }

  static rc4Hex(key, data) {
    const k = Buffer.from(key, 'utf8');
    const s = Array.from({ length: 256 }, (_, i) => i);
    let j = 0;
    for (let i = 0; i < 256; i++) {
      j = (j + s[i] + k[i % k.length]) % 256;
      [s[i], s[j]] = [s[j], s[i]];
    }
    const p = Buffer.from(data, 'utf8');
    let x = 0, y = 0;
    const out = Buffer.alloc(p.length);
    for (let idx = 0; idx < p.length; idx++) {
      x = (x + 1) % 256;
      y = (y + s[x]) % 256;
      [s[x], s[y]] = [s[y], s[x]];
      out[idx] = p[idx] ^ s[(s[x] + s[y]) % 256];
    }
    return out.toString('hex').toUpperCase();
  }

  async init() {
    const ts = String(Math.floor(Date.now() / 1000));
    const sign = A7Client.md5(this.appId + this.appKey + ts + this.appKey);
    const body = new URLSearchParams({
      AppId: this.appId, AppKey: this.appKey, TimeStamp: ts, Sign: sign,
    });
    const resp = await fetch(this.base, {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body,
    });
    const json = await resp.json();
    if (json.code !== 200) throw new Error(`Init 失败: ${json.code} ${json.message}`);
    this.apiPassword = json.data.api_password;
    return this.apiPassword;
  }

  async call(action, params = {}) {
    if (!this.apiPassword) await this.init();
    let plain = 'action=' + action;
    for (const [k, v] of Object.entries(params)) {
      plain += '&' + k + '=' + encodeURIComponent(String(v));
    }
    const ts = String(Math.floor(Date.now() / 1000));
    const data = A7Client.rc4Hex(this.apiPassword, plain);
    const sign = A7Client.md5(this.apiPassword + ts + data);
    const body = new URLSearchParams({ TimeStamp: ts, Data: data, Sign: sign });
    const resp = await fetch(this.base, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'X-Api-Password': this.apiPassword,
      },
      body,
    });
    return resp.json();
  }
}

module.exports = { A7Client };

使用示例

javascript
const { A7Client } = require('./a7client');

(async () => {
  const client = new A7Client('150018', 'YOUR_APP_KEY');
  const resp = await client.call('SingleLogin', {
    Card: 'UTDE-7TCX-N5AT-ZDSP',
    Mac: 'TEST-ABC-123',
    DeviceName: 'MyPC',
  });
  if (resp.code === 200) {
    console.log('token:', resp.data.token);
  } else {
    console.log('失败:', resp.code, resp.message);
  }
})();

ESM / TypeScript

require 改为 import,类型声明可基于 resp: { code: number; message: string; data: Record<string, any> }

注意事项

  • apiPassword 仅保存在实例属性,请勿写入磁盘。
  • fetch 需 Node.js 18+;老版本请改用 axios / node-fetch
  • 更多接口参数见 API 参考

相关链接

A7验证 · 软件授权与网络验证平台