第4章:接入与认证
4.1 接入流程概述
WMS 对外 API 采用 Token 的安全认证机制。
客户系统在调用接口前,需要先向我司申请 API Key / Secret,并通过认证接口获取访问 Token。
后续所有业务接口调用时,均需在请求头中携带 Token。
系统目前支持两种访问模式:
| 模式 | 说明 |
|---|---|
| 生产环境(Production) | 用于正式业务场景,数据真实、受权限控制。 |
| 测试环境(Sandbox) | 用于开发调试,接口逻辑与生产一致,但不产生真实业务数据。 |
4.2 凭证申请
在接入 WMS API 之前,开发者需向我司技术支持团队申请访问凭证。
申请时需提供以下信息:
| 参数 | 说明 |
|---|---|
| 公司名称 | 用于标识合作方身份 |
| 系统名称 | 对接的 ERP / OMS / TMS 系统名称 |
| 联系人 | 技术对接负责人姓名 |
| 联系邮箱 | 接收 API Key / Secret 的邮箱地址 |
| 使用场景 | 简要说明调用接口的目的与范围 |
说明:
- 每个合作方将被分配独立的 API Key 与 API Secret。
- 以上信息审核通过后,我司将邮件发送认证信息。
4.3 Token 获取接口
获取 Token 是所有业务接口调用的前提。外部系统需要使用我司分配的 API Key 和 API Secret 来获取访问 Token。
请求地址: POST /ucauth/authc/account/createToken
请求头(Headers):
| Header | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| X-Api-Key | String | 是 | 我司分配的应用标识(API Key) |
| X-Api-Secret | String | 是 | 我司分配的应用密钥(API Secret) |
| Content-Type | String | 是 | 固定为 application/json |
请求示例:
# 沙箱环境示例
curl -X POST "https://api.sandbox.onixportltl.com/ucauth/authc/account/createToken" \
-H "X-Api-Key: 3F2504E04F8911D39A0C0305E82C3301" \
-H "X-Api-Secret: L9Gf7bQ2xU3VjK1Yp8nR5wT0eXz6Hq2fAaJdKsLmQpU" \
-H "Content-Type: application/json"
# 生产环境示例
curl -X POST "https://api.onixportsystem.com/ucauth/authc/account/createToken" \
-H "X-Api-Key: your-api-key" \
-H "X-Api-Secret: your-api-secret" \
-H "Content-Type: application/json"
响应格式:
成功响应:
{
"success": true,
"errorCode": null,
"errorMsg": null,
"result": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 86400
}
}
失败响应:
{
"success": false,
"errorCode": 1404,
"errorMsg": "Email address or password is not valid."
}
响应字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| success | Boolean | 请求是否成功 |
| errorCode | Integer | 错误码。当 success=true 时,该字段为 null;当 success=false 时,该字段有值 |
| errorMsg | String | 错误信息。当 success=true 时,该字段为 null;当 success=false 时,该字段有值 |
| result | Object | 成功时的响应数据 |
| result.accessToken | String | 访问令牌,用于后续接口调用 |
| result.expiresIn | Long | Token 有效期(单位:秒),当前固定为 86400 秒(24小时) |
说明:
expiresIn:Token 从当前时间开始的有效期,单位为秒,当前固定为 86400 秒(24小时)- 调用方应记录 Token 获取时间和
expiresIn值,自行计算失效时间 - 建议在 Token 失效前 1 分钟自动刷新,避免接口调用中断
常见错误码:
| 错误码 | 说明 |
|---|---|
| 1404 | API Key 或 API Secret 无效 |
| 1405 | 账户已被锁定,请联系系统管理员 |
| 1406 | 账户邮箱需要验证 |
| 1412 | 账户已被暂停,请联系销售获取更多信息 |
| 1440 | 登录失败次数过多,请稍后再试 |
说明:
- Token 有效期为 24 小时(86400 秒);
- 建议将 Token 缓存到 Redis 或本地缓存中,缓存过期时间设置为
expiresIn - 5分钟(例如:86400 - 300 = 86100秒); - 当缓存过期时,说明 Token 即将失效,自动重新获取 Token;
- Token 到期后需重新调用此接口获取新的 Token;
- 所有业务接口均需在请求头中携带:
Authorization: Bearer {accessToken}; - 请妥善保管 API Key 和 API Secret,避免泄露。
4.4 业务接口请求头要求
获取 Token 后,调用业务接口时需在请求头中携带以下信息:
| Header | 是否必填 | 说明 |
|---|---|---|
| Content-Type | 是 | 固定为 application/json |
| Authorization | 是 | Bearer {accessToken},其中 {accessToken} 为通过 createToken 接口获取的令牌 |
注意: 业务接口的请求头要求可能因具体接口而异,请参考各业务接口的详细文档。
4.5 Token 失效与续期
4.5.1 Token 失效时间
- Token 有效期为 24 小时(86400 秒);
- 创建 Token 时,响应中会返回
expiresIn字段(单位:秒),表示 Token 的有效期; - 调用方应记录 Token 获取时间(Unix 时间戳)和
expiresIn值,自行计算失效时间。
4.5.2 Token 刷新策略
建议实现:
1. 缓存 Token:将 Token 缓存到 Redis 或本地缓存中
2. 设置缓存过期时间:缓存过期时间应小于 expiresIn 值,例如提前 5 分钟失效
- 缓存过期时间 = expiresIn - 5分钟(300秒)
- 例如:expiresIn = 86400秒(24小时),则缓存过期时间 = 86100秒(23小时55分钟)
3. 自动刷新机制:当缓存过期时,说明 Token 即将失效,自动重新获取 Token
4. 缓存更新:获取新 Token 后,更新缓存并重新设置缓存过期时间
优势:
- 利用缓存机制自动管理 Token 生命周期
- 无需手动计算剩余时间,缓存过期即表示需要刷新
- 支持分布式部署,多个服务实例共享同一个 Token
示例代码:
// 示例代码 - 使用 Redis 缓存
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.TimeUnit;
public class TokenService {
private static final String REDIS_KEY = "wms_api_token";
private static final int CACHE_BUFFER = 5 * 60; // 提前5分钟失效(300秒)
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private TokenApiClient tokenApiClient;
/**
* 获取 Token,优先从缓存获取,缓存不存在或过期时重新获取
*/
public String getToken() {
// 1. 尝试从缓存获取 Token
String token = redisTemplate.opsForValue().get(REDIS_KEY);
if (token != null && !token.isEmpty()) {
// 缓存中存在,直接返回
return token;
}
// 2. 缓存不存在或已过期,重新获取 Token
TokenResponse tokenResponse = tokenApiClient.getNewToken();
token = tokenResponse.getAccessToken();
Long expiresIn = tokenResponse.getExpiresIn();
// 3. 计算缓存过期时间(提前5分钟失效)
long cacheExpireTime = expiresIn - CACHE_BUFFER;
// 4. 将 Token 存入缓存,设置过期时间
redisTemplate.opsForValue().set(REDIS_KEY, token, cacheExpireTime, TimeUnit.SECONDS);
return token;
}
}
// 使用示例
@Autowired
private TokenService tokenService;
String token = tokenService.getToken();
// 使用 token 调用业务接口
// 示例代码 - 使用本地缓存(内存)
import java.util.concurrent.atomic.AtomicLong;
public class TokenCacheService {
private static final int CACHE_BUFFER = 5 * 60; // 提前5分钟失效(300秒)
private String token;
private AtomicLong expireTime = new AtomicLong(0);
private final Object lock = new Object();
@Autowired
private TokenApiClient tokenApiClient;
/**
* 获取 Token,优先从本地缓存获取,缓存过期时重新获取
*/
public String getToken() {
long now = System.currentTimeMillis() / 1000; // 当前时间戳(秒)
// 1. 检查缓存是否有效
if (token != null && now < expireTime.get()) {
return token;
}
// 2. 缓存无效,重新获取 Token(加锁防止并发)
synchronized (lock) {
// 双重检查,避免重复获取
if (token != null && now < expireTime.get()) {
return token;
}
TokenResponse tokenResponse = tokenApiClient.getNewToken();
Long expiresIn = tokenResponse.getExpiresIn();
// 3. 计算缓存过期时间(提前5分钟失效)
long cacheExpireTime = now + expiresIn - CACHE_BUFFER;
// 4. 更新缓存
this.token = tokenResponse.getAccessToken();
this.expireTime.set(cacheExpireTime);
return this.token;
}
}
}
// 使用示例
@Autowired
private TokenCacheService tokenCacheService;
String token = tokenCacheService.getToken();
// 使用 token 调用业务接口
4.5.3 Token 失效处理
- 若接口返回 401 或业务码 10001(Token Invalid),说明 Token 已失效,需重新调用
/ucauth/authc/account/createToken接口获取新 Token; - 旧 Token 失效后不可重复使用,必须重新获取;
- 频繁重复调用将触发防刷机制,建议合理缓存 Token,避免频繁请求认证接口。
4.6 安全建议
- 妥善保管 API Key 和 API Secret,严禁在前端或公共仓库中暴露;
- 所有接口调用务必使用 HTTPS;
- 可在我司配置 IP 白名单 限制访问;
- 建议服务端使用缓存机制保存 Token,以减少频繁认证请求;
- Token 应存储在服务端,避免在客户端暴露。