在自动化运维、设备批量管理、账号授权等场景中,卡密是实现设备时长、脚本权限、用户授权的核心载体。开发者可在自有 Java 后台无缝对接卡密创建、查询、转移、管理等能力,实现自动化授权、分销系统、设备计费、权限管控等业务闭环。本文从接入准备、核心接口解析、Java 实战 Demo、异常处理到最佳实践,全方位讲解如何在后台服务中调用冰狐 OpenAPI 完成卡密全生命周期操作,助力开发者快速落地集成。
一、冰狐 OpenAPI 与卡密核心认知
1. 冰狐 OpenAPI 基础
冰狐智能辅助 OpenAPI 是平台提供的后端服务调用接口 ,支持设备管理、用户管理、卡密操作、脚本执行、微服务调用等能力,所有接口统一返回 JSON 格式,成功 state=1,失败 state=-1,data 字段承载返回数据或错误描述,接入门槛低、适配性强,适合 Java、Python、Go 等多种后端语言集成。
2. 卡密核心价值
冰狐卡密是设备授权、时长兑换、脚本权限绑定的凭证,核心能力包括:
- 绑定设备可用时长,控制设备使用周期;
- 限定支持的脚本,实现脚本权限精细化管控;
- 支持主账户 / 子账户分配,适配多用户分销场景;
- 可批量创建、查询、转移,满足自动化运营需求。
卡密相关接口是 OpenAPI 的高频核心模块,涵盖创建卡密、获取卡密列表、转移卡密三大核心能力,覆盖卡密全生命周期管理。
3. 接入前置条件
- 注册冰狐智能辅助开发者账号,获取clientKey(开发者 Key) 和clientSecret(开发者密钥);
- 完成开发者认证,开通 OpenAPI 调用权限;
- 准备 Java 开发环境(JDK8+),引入 HTTP 请求、JSON 解析依赖;
- 牢记:get_token 接口禁止频繁调用,否则会被系统拉黑 IP。
二、卡密相关 OpenAPI 核心接口详解
卡密操作依赖Token 认证 ,所有接口必须携带有效 accessToken,调用流程为:获取 Token→卡密操作→Token 刷新(过期时),以下是卡密核心接口完整参数说明。
1. 前置接口:获取 Token(必调)
- 请求地址:GET /api/get_token
- 请求参数:clientKey(必填)、clientSecret(必填)
- 响应参数:accessToken(访问凭证)、refreshToken(刷新凭证)、expiresIn(过期时间,秒)
- 注意:Token 有过期时间,需缓存 accessToken,过期后用 refreshToken 刷新,避免重复调用 get_token。
2. 前置接口:刷新 Token
- 请求地址:GET /api/refresh_token
- 请求参数:clientKey(必填)、refreshToken(必填)
- 作用:替换过期 accessToken,保证接口调用连续性。
3. 卡密核心接口
(1)创建卡密
-
请求地址:GET /api/passport/create
-
核心功能:批量生成卡密,绑定时长、脚本权限、所属账户
-
请求参数:
参数名 类型 必填 说明 clientKey string 是 开发者 Key accessToken string 是 访问 Token hours integer 是 卡密时长(分钟) count integer 否 创建数量,默认 1 supportScripts string 否 支持脚本,多脚本用 #分割 childOpenId string 否 子账户 OpenID,默认主账户 -
响应:data=1 成功,0 失败。
(2)获取卡密列表
- 请求地址:GET /api/passport/list
- 核心功能:分页查询卡密,支持按子账户、设备筛选
- 请求参数:clientKey、accessToken(必填);childOpenId、uuid、cursor、count(选填)
- 响应:返回卡密数组(含卡密、时长、创建时间等)、总数量。
(3)转移卡密
- 请求地址:GET /api/passport/transfer
- 核心功能:将卡密分配给子账户,实现权限下放
- 请求参数:clientKey、accessToken、passport(卡密)、openId(子账户 ID)(均必填)
- 响应:data=1 成功,0 失败。
三、Java 后端集成 Demo(完整可运行)
本文基于SpringBoot 2.7.x + OkHttp3 + Fastjson2 实现,封装冰狐 OpenAPI 客户端,完成 Token 管理、卡密创建 / 查询 / 转移全流程,代码可直接嵌入生产环境。
1. 项目依赖(Maven)
XML
<!-- SpringBoot核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- OkHttp3 HTTP客户端 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
<!-- Fastjson2 JSON解析 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.24</version>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.20</version>
</dependency>
2. 配置文件(application.yml)
# 冰狐OpenAPI配置
binghu:
open-api:
base-url: https://aznfz.com
client-key: 你的开发者clientKey
client-secret: 你的开发者clientSecret
# Token缓存时间(提前5分钟过期)
token-cache-expire: 3500
3. 核心配置类
java
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 冰狐OpenAPI配置类
*/
@Data
@Component
@ConfigurationProperties(prefix = "binghu.open-api")
public class BingHuOpenApiConfig {
/**
* 接口基础地址
*/
private String baseUrl;
/**
* 开发者Key
*/
private String clientKey;
/**
* 开发者密钥
*/
private String clientSecret;
/**
* Token缓存过期时间(秒)
*/
private Long tokenCacheExpire;
}
4. Token 实体与响应实体
java
import lombok.Data;
/**
* 冰狐Token实体
*/
@Data
public class BingHuToken {
/**
* 访问Token
*/
private String accessToken;
/**
* 刷新Token
*/
private String refreshToken;
/**
* 过期时间(秒)
*/
private Integer expiresIn;
/**
* 创建时间戳
*/
private Long createTime;
}
/**
* 冰狐接口通用响应
*/
@Data
public class BingHuResponse<T> {
/**
* 状态:1成功,-1失败
*/
private Integer state;
/**
* 数据
*/
private T data;
}
5. 卡密实体
java
import lombok.Data;
/**
* 冰狐卡密实体
*/
@Data
public class BingHuPassport {
/**
* 设备UUID
*/
private String uuid;
/**
* 卡密
*/
private String skv;
/**
* 更新时间
*/
private Integer verifyTime;
/**
* 创建时间
*/
private Integer time;
/**
* 卡密有效时长(分钟)
*/
private Integer hours;
}
6. 冰狐 OpenAPI 客户端
java
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import com.alibaba.fastjson2.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 冰狐OpenAPI客户端
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class BingHuOpenApiClient {
private final BingHuOpenApiConfig openApiConfig;
private final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
/**
* Token本地缓存
*/
private final TimedCache<String, BingHuToken> tokenCache = CacheUtil.newTimedCache(
openApiConfig.getTokenCacheExpire() * 1000
);
private static final String TOKEN_CACHE_KEY = "binghu_open_api_token";
/**
* 获取有效Token(缓存+自动刷新)
*/
public String getAccessToken() {
BingHuToken token = tokenCache.get(TOKEN_CACHE_KEY);
if (token == null) {
token = getTokenFromApi();
tokenCache.put(TOKEN_CACHE_KEY, token);
}
return token.getAccessToken();
}
/**
* 调用接口获取Token
*/
private BingHuToken getTokenFromApi() {
String url = String.format("%s/api/get_token?clientKey=%s&clientSecret=%s",
openApiConfig.getBaseUrl(),
openApiConfig.getClientKey(),
openApiConfig.getClientSecret());
try {
Request request = new Request.Builder().get().url(url).build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("获取Token失败,HTTP状态码:" + response.code());
}
String responseBody = response.body().string();
BingHuResponse<BingHuToken> result = JSON.parseObject(responseBody,
JSON.parseObject(responseBody).getClass(), BingHuToken.class);
if (result.getState() != 1) {
throw new RuntimeException("获取Token失败,错误信息:" + result.getData());
}
BingHuToken token = result.getData();
token.setCreateTime(System.currentTimeMillis());
return token;
}
} catch (Exception e) {
log.error("获取冰狐Token异常", e);
throw new RuntimeException("获取Token异常:" + e.getMessage());
}
}
/**
* 发送GET请求(通用)
*/
private <T> BingHuResponse<T> sendGetRequest(String path, Map<String, String> params, Class<T> dataClass) {
// 拼接公共参数
params.put("clientKey", openApiConfig.getClientKey());
params.put("accessToken", getAccessToken());
// 构建URL
StringBuilder urlBuilder = new StringBuilder(openApiConfig.getBaseUrl()).append(path).append("?");
params.forEach((k, v) -> urlBuilder.append(k).append("=").append(v).append("&"));
String url = urlBuilder.substring(0, urlBuilder.length() - 1);
try {
Request request = new Request.Builder().get().url(url).build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("接口调用失败,HTTP状态码:" + response.code());
}
String responseBody = response.body().string();
return JSON.parseObject(responseBody,
JSON.parseObject(responseBody).getClass(), dataClass);
}
} catch (Exception e) {
log.error("调用冰狐接口[{}]异常", path, e);
throw new RuntimeException("接口调用异常:" + e.getMessage());
}
}
// ==================== 卡密相关接口 ====================
/**
* 创建卡密
* @param minutes 卡密时长(分钟)
* @param count 创建数量
* @param supportScripts 支持脚本(多脚本#分割)
* @param childOpenId 子账户ID
* @return true成功 false失败
*/
public Boolean createPassport(Integer minutes, Integer count, String supportScripts, String childOpenId) {
Map<String, String> params = new HashMap<>();
params.put("hours", String.valueOf(minutes));
if (count != null) {
params.put("count", String.valueOf(count));
}
if (supportScripts != null) {
params.put("supportScripts", supportScripts);
}
if (childOpenId != null) {
params.put("childOpenId", childOpenId);
}
BingHuResponse<Integer> response = sendGetRequest("/api/passport/create", params, Integer.class);
return response.getState() == 1 && response.getData() == 1;
}
/**
* 获取卡密列表
* @param childOpenId 子账户ID
* @param uuid 设备UUID
* @param cursor 分页游标
* @param count 页大小
* @return 卡密列表+总数
*/
public Map<String, Object> getPassportList(String childOpenId, String uuid, Integer cursor, Integer count) {
Map<String, String> params = new HashMap<>();
if (childOpenId != null) {
params.put("childOpenId", childOpenId);
}
if (uuid != null) {
params.put("uuid", uuid);
}
if (cursor != null) {
params.put("cursor", String.valueOf(cursor));
}
if (count != null) {
params.put("count", String.valueOf(count));
}
BingHuResponse<Map<String, Object>> response = sendGetRequest("/api/passport/list", params, Map.class);
return response.getData();
}
/**
* 转移卡密给子账户
* @param passport 卡密
* @param childOpenId 子账户ID
* @return true成功 false失败
*/
public Boolean transferPassport(String passport, String childOpenId) {
Map<String, String> params = new HashMap<>();
params.put("passport", passport);
params.put("openId", childOpenId);
BingHuResponse<Integer> response = sendGetRequest("/api/passport/transfer", params, Integer.class);
return response.getState() == 1 && response.getData() == 1;
}
}
7. 测试接口(Controller)
java
import lombok.RequiredArgsConstructor;
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.Map;
/**
* 冰狐卡密测试接口
*/
@RestController
@RequestMapping("/binghu/passport")
@RequiredArgsConstructor
public class BingHuPassportController {
private final BingHuOpenApiClient openApiClient;
/**
* 创建卡密
*/
@GetMapping("/create")
public Boolean createPassport(
@RequestParam Integer minutes,
@RequestParam(defaultValue = "1") Integer count,
@RequestParam(required = false) String supportScripts,
@RequestParam(required = false) String childOpenId) {
return openApiClient.createPassport(minutes, count, supportScripts, childOpenId);
}
/**
* 获取卡密列表
*/
@GetMapping("/list")
public Map<String, Object> getPassportList(
@RequestParam(required = false) String childOpenId,
@RequestParam(required = false) String uuid,
@RequestParam(defaultValue = "0") Integer cursor,
@RequestParam(defaultValue = "-1") Integer count) {
return openApiClient.getPassportList(childOpenId, uuid, cursor, count);
}
/**
* 转移卡密
*/
@GetMapping("/transfer")
public Boolean transferPassport(
@RequestParam String passport,
@RequestParam String childOpenId) {
return openApiClient.transferPassport(passport, childOpenId);
}
}
四、Demo 运行与测试
- 替换配置文件中clientKey 和clientSecret为自己的开发者凭证;
- 启动 SpringBoot 项目,访问测试接口:
- 创建卡密:
https://aznfz.com /api/passport/create?minutes=60&count=5&supportScripts=抖音#快手 - 查询卡密:
https://aznfz.com/api/passport/list - 转移卡密:
https://aznfz.com/api/passport/transfer?passport=XXX&childOpenId=XXX
- 创建卡密:
- 查看响应结果,state=1 且 data 返回对应数据即调用成功。
五、生产环境最佳实践
1. Token 管理优化
- 本地缓存 Token,禁止频繁调用 get_token,避免 IP 被拉黑;
- 提前刷新 Token(如过期前 5 分钟),防止业务中断;
- 分布式环境下,可改用 Redis 缓存 Token,保证多实例一致性。
2. 异常处理
- 捕获接口调用异常,增加重试机制(最多 3 次);
- 针对 state=-1 的错误,记录日志并返回友好提示;
- 处理网络超时、参数错误、Token 过期等常见问题。
3. 安全规范
- clientKey 和 clientSecret严禁硬编码,放入配置中心或环境变量;
- 接口调用日志脱敏,不打印敏感凭证;
- 卡密数据加密存储,防止泄露。
4. 性能优化
- 批量创建卡密时,合理设置 count 值,避免单次创建过多;
- 卡密列表查询使用分页,减少数据传输量;
- 复用 OkHttpClient 实例,避免频繁创建连接。
六、常见问题排查
- 获取 Token 失败:检查 clientKey、clientSecret 是否正确,确认开发者权限已开通;
- IP 被拉黑:减少 get_token 调用频率,改用缓存 + 刷新机制;
- 卡密创建失败:检查 hours 参数是否为正整数,supportScripts 格式是否正确;
- 转移卡密失败:确认卡密未被使用、子账户 OpenID 有效。
七、总结
通过冰狐智能辅助 OpenAPI,Java 后端可快速实现卡密创建、查询、转移、权限绑定等全流程操作,适配自动化设备管理、授权分销、脚本管控等业务场景。本文提供的 Demo 已封装 Token 自动缓存、刷新、通用请求逻辑,开发者只需替换配置即可快速集成,大幅降低接入成本。